这是代码,
#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;
}
首次使用BUILD_BUG_ON(条件)宏如果sizeof struct不等于8则抛出编译错误,因为条件将评估为true。但即使我提供真实条件,第二次使用宏也不会抛出编译错误。我无法理解这种行为。有人可以解释一下吗?
答案 0 :(得分:5)
AuthenticatesUsers
宏旨在实现编译时断言。
给定一个可以在编译时计算的参数,如果参数为非零(true),则会导致编译时失败,如果参数为非零(false),则不执行任何操作。
它不适用于在运行时计算的参数。
BUILD_BUG_ON
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
是两个逻辑&#34;不是&#34;运营商;它们可以将!!
的值标准化为0
,将任何非零值标准化为0
。
如果结果条件为1
(真),则1
的值为1 - 2*!!(condition)
。如果条件为-1
(false),则值为0
。
数组可能没有负(或零)大小。一些编译器可能支持零长度数组作为扩展;这个宏确保即使是这样的编译器也能诊断出错误。如果size是常量表达式,则具有负大小的数组是违反约束的,需要编译时诊断。
如果表达式为false,则没有错误;宏扩展为一个什么都不做的表达式。如果表达式为真并且是常量表达式,则宏的扩展会尝试定义负数大小的数组,从而导致编译时错误。
如果表达式不是常量,则宏不起作用。 C(C99及更高版本)允许可变长度数组(VLA)。不允许零或负长度的VLA,但是通常不能在编译时检测到定义这样的VLA。这是未定义的行为 - 在这种情况下,它可能什么也不做。 (只是为了使文件范围内不允许使用VLA。)
理想情况下,宏应附有解释如何使用它的文档。该文档应该解释该参数必须是编译时表达式。
底线:您应该只将此宏与常量表达式参数一起使用。 (要测试运行时表达式,可以使用1
。)如果使用值为零的非常量表达式,则行为未定义;最可能的结果是预期的&#34;断言&#34;不会触发,也不会检测到错误。
答案 1 :(得分:1)
我认为你的方法完全不自然 这是糟糕的代码,即使它会起作用 您可以尝试更自然的方法来处理错误。
断言
宏assert
在运行时测试条件,并在测试失败时显示错误消息。
#include <assert.h>
int main(void)
{
assert((sizeof(struct my_struct) % 8) != 0);
}
static_assert
在C11投诉编制器中,static_assert(condition, "Error message")
为常量表达式做了你想做的事情:
static_assert((sizeof(struct my_struct) % 8) != 0, "Wrong struct");
#if和#error
也可以使用#if
和#error
编译器指令,但在这种情况下我不建议你,因为sizeof
不理解#if
。
语法为:
#if some_condition // Put an integer constant expression readable by an #if.
# error This is wrong.
#endif
这三种方法中的一些必须满足您的需求。
答案 2 :(得分:0)
更改
BUILD_BUG_ON(cond);
到
BUILD_BUG_ON(1);
获得预期的行为。
当cond
值仅在运行时可用时,将在未优化的构建中生成计算所需sizeof
的代码(并将其结果丢弃),或者在优化时完全忽略整个表达式生成。