这是代码,
#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;
}
Run Code Online (Sandbox Code Playgroud)
第一次使用BUILD_BUG_ON(条件)宏如果sizeof struct不等于8则抛出编译错误,因为条件将评估为true.但即使我提供真实条件,第二次使用宏也不会抛出编译错误.我无法理解这种行为.谁能解释一下?
该BUILD_BUG_ON宏旨在实现编译时断言.
给定一个可以在编译时计算的参数,如果参数为非零(true),则会导致编译时失败,如果参数为非零(false)则不会执行任何操作.
它不适用于在运行时计算的参数.
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
Run Code Online (Sandbox Code Playgroud)
这!!是两个逻辑"非"运算符; 它们具有将0to 的值0和任何非零值标准化的效果1.
如果所得到的条件是1(真),则该值1 - 2*!!(condition)是-1.如果条件是0(假),则值为1.
数组可能没有负(或零)大小.一些编译器可能支持零长度数组作为扩展; 这个宏确保即使是这样的编译器也能诊断出错误.如果size是常量表达式,则具有负大小的数组是违反约束的,需要编译时诊断.
如果表达式为false,则没有错误; 宏扩展为一个什么都不做的表达式.如果表达式为true 并且是常量表达式,则宏的扩展尝试定义负大小的数组,从而导致编译时错误.
如果表达式不是常量,则宏不起作用.C(C99和更高版本)允许可变长度数组(VLA).不允许零或负长度的VLA,但是通常不能在编译时检测到定义这样的VLA.它是未定义的行为 - 在这种情况下,它可能什么都不做.(只是为了使文件范围内不允许使用VLA.)
理想情况下,宏应附有解释如何使用它的文档.该文档应该解释该参数必须是编译时表达式.
底线:您应该只将此宏与常量表达式参数一起使用.(要测试运行时表达式,可以使用assert().)如果使用值为零的非常量表达式,则行为未定义; 最可能的结果是预期的"断言"不会触发,并且不会检测到错误.
改变
BUILD_BUG_ON(cond);
Run Code Online (Sandbox Code Playgroud)
到
BUILD_BUG_ON(1);
Run Code Online (Sandbox Code Playgroud)
以获得预期的行为。
当该cond值仅在运行时可用时,sizeof会在未优化的构建中生成计算所需值的代码(并丢弃其结果),或者在优化的构建中完全忽略整个表达式。