Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C宏在不同情况下的不同行为_C - Fatal编程技术网

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

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 mai

这是代码

#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;
}
#包括
#包括
#定义构建错误(条件)((无效)大小(字符[1-2*!!(条件)])
结构我的结构{
INTA,b;
//字符c;
};
int main(){
布尔康德=1;
构建错误((sizeof(struct my_struct)%8)!=0);
构建错误(cond);
返回0;
}
如果sizeof struct不等于8,则第一次使用BUILD_BUG_ON(condition)宏会引发编译错误,因为条件的计算结果将为true。但第二次使用宏不会抛出编译错误,即使我提供了真实的条件。我无法理解这种行为。有人能解释一下吗?

BUILD_BUG_ON(cond);

获得预期的行为


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

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

断言

assert
在运行时测试条件,如果测试失败,则显示错误消息

 #include <assert.h>
 int main(void)
 {
     assert((sizeof(struct my_struct) % 8) != 0);
 }
#如果和#错误

同样可以使用
#if
#error
编译器指令,但在这种情况下我不建议您,因为
#if
不理解
的大小

语法是:

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

这三种方法中的某些方法必须满足您的需要。

宏的
BUILD\u BUG\u ON
旨在实现编译时断言

给定一个可在编译时计算的参数,如果该参数为非零(true),则会导致编译时失败;如果该参数为非零(false),则不会执行任何操作

它不适用于在运行时计算的参数

#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
是两个逻辑“not”运算符;它们的作用是将
0
的值标准化为
0
,将任何非零值标准化为
1

如果结果条件为
1
(真),则
1-2*的值!!(条件)
-1
。如果条件为
0
(false),则值为
1

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

如果表达式为false,则没有错误;宏将扩展为不执行任何操作的表达式。如果表达式为true且为常量表达式,则宏的扩展将尝试定义负大小的数组,从而导致编译时错误

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

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


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

似乎条件需要是编译时常量表达式才能使错误“工作”。
printf(“%ld\n”,sizeof(char[1-2*(cond)])给出
-1
。我不知道这是可能的。此外,当条件为动态真时,此代码只是具有未定义的行为,因为可变长度数组的大小必须大于零(参见6.7.6.2/5)。您似乎缺少BUILD_BUG_ON和普通assert()之间的区别.这三种方法都不可能奏效<代码>断言
在运行时计算;OP希望在编译时检测错误
static_assert
是最近才添加的;OP很可能使用了不支持它的编译器
#如果
#错误
,正如您所说,请不要识别
的大小。我见过类似的技术用于模拟编译时断言。它们是丑陋的,但丑陋在宏观定义中是孤立的。这是一种完全合法的技术。此外,您还没有回答OP的问题,即代码是如何工作的。您可以说这是一段糟糕的代码,但即使是linux内核在编译时断言中也使用了类似的技巧。@HolyBlackCat:您陷入了诉诸权威的谬论。@pablo1977对不起,我的措辞不完全清楚。我不是说OP的代码是好的。但这是在C11之前生成编译时断言的唯一方法。linux内核中存在类似的代码这一事实表明,它在一些实际软件中得到了应用。虽然OP的方法是不可避免的,但可以改进他的代码。我将它重写为
#define BUILD_BUG_ON(x)do{struct{int:-(x);}a;sizeof a;}而(0)
。此版本在C++中工作,如果表达式中使用非const值,则会发出错误。这似乎比否定数组方法更好,主要是因为它不允许运行时评估(如前所述)。为避免有关未使用值(GCC)的警告,请强制转换sizeof的结果
#if some_condition // Put an integer constant expression readable by an #if.
#  error This is wrong.
#endif
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))