c - C 宏在不同情况下的不同行为

标签 c

这是代码,

#include<stdio.h>
#include<stdbool.h>

#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))                                                               

struct my_struct {
    int a, b;
//  char c;
};

int main() {
    bool cond = 1;
    BUILD_BUG_ON((sizeof(struct my_struct) % 8) != 0);
    BUILD_BUG_ON(cond);
    return 0;
}

如果 sizeof struct 不等于 8,则首次使用 BUILD_BUG_ON(condition) 宏会抛出编译错误,因为条件的计算结果为真。但是即使我提供了真实条件,第二次使用宏也不会引发编译错误。我无法理解这种行为。谁能解释一下?

最佳答案

BUILD_BUG_ON 宏旨在实现编译时断言。

给定一个可以在编译时求值的参数,如果参数不为零 (true),它会导致编译时失败,如果参数不为零 (false),则什么都不做。

它不适用于在运行时评估的参数。

#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))

!! 是两个逻辑“非”运算符;它们的作用是将 0 的值规范化为 0,并将任何非零值规范化为 1

如果结果条件为 1(真),则 1 - 2*!!(condition) 的值为 -1 .如果条件为 0(假),则值为 1

数组的大小不能为负(或零)。一些编译器可能支持零长度数组作为扩展;这个宏确保即使是这样的编译器也能诊断错误。如果大小是常量表达式,则具有负大小的数组违反约束,需要编译时诊断。

如果表达式为假,则没有错误;宏扩展为一个什么都不做的表达式。如果表达式为真并且是常量表达式,则宏的扩展会尝试定义一个负大小的数组,从而导致编译时错误。

如果表达式不是常量,则宏不起作用。 C(C99 及更高版本)允许可变长度数组 (VLA)。零或负长度的 VLA 是不允许的,但定义这样的 VLA 通常无法在编译时检测到。这是未定义的行为——在这种情况下,它可能什么都不做。 (只是为了使事情复杂化,VLA 在文件范围内是不允许的。)

理想情况下,宏应该附有说明如何使用它的文档。该文档应说明参数必须是编译时表达式。

底线:您应该仅将此宏与常量表达式参数一起使用。 (要测试运行时表达式,您可以使用 assert()。)如果您使用具有零值的非常量表达式,则行为未定义;最可能的结果是预期的“断言”不会触发并且不会检测到错误。

关于c - C 宏在不同情况下的不同行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31494179/

相关文章:

c - 如何正确地释放进程之间的共享内存?

C - 内存设置与免费

c - 将函数作为参数传递

c - 在二维数组中打印字符串的各种构象

c - 提取文件 C 中字母之间的数字

为 OpenGL 使用正确计算模型和 View 矩阵?

c++ - 如何开始使用多线程编程?

c - 监听两个特定端口的套接字服务器

c - 需要写入一个字符串常量,我该如何解决这个问题?

java - 为什么函数 main() 的名称为 main