繁体   English   中英

不同情况下C宏的不同行为

[英]Different behaviour of C macro for different cases

这是代码,

#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。 但即使我提供真实条件,第二次使用宏也不会抛出编译错误。 我无法理解这种行为。 谁能解释一下?

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

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

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

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

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

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

我认为你的方法完全不自然。
这是糟糕的代码,即使它会起作用。
您可以尝试更自然的方法来处理错误。

断言

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编译器指令,但在这种情况下我不建议你,因为#if不理解sizeof

语法是:

#if some_condition // Put an integer constant expression readable by an #if.
#  error This is wrong.
#endif

这三种方法中的一些必须满足您的需求。

更改

BUILD_BUG_ON(cond);

BUILD_BUG_ON(1);

获得预期的行为。

cond值仅在运行时可用时,将在未优化的构建中生成计算所需sizeof的代码(并将其结果丢弃),或者在优化的构建中完全忽略整个表达式。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM