简体   繁体   English

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

[英]Different behaviour of C macro for different cases

This is the code, 这是代码,

#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;
}

first use of BUILD_BUG_ON(condition) macro is throwing compilation error if sizeof struct is not equal to 8 as the condition will evaluate to true. 第一次使用BUILD_BUG_ON(条件)宏如果sizeof struct不等于8则抛出编译错误,因为条件将评估为true。 but second use of macro is not throwing compilation error even if i am providing true condition. 但即使我提供真实条件,第二次使用宏也不会抛出编译错误。 I am not able to understand this behaviour. 我无法理解这种行为。 Can someone explain? 谁能解释一下?

The BUILD_BUG_ON macro is intended to implement a compile-time assertion. BUILD_BUG_ON在实现编译时断言。

Given an argument that can be evaluated at compile time, it causes a compile-time failure if the argument is non-zero (true), and does nothing if the argument is non-zero (false). 给定一个可以在编译时计算的参数,如果参数为非零(true),则会导致编译时失败,如果参数为非零(false)则不会执行任何操作。

It does not work for an argument that is evaluated at run time. 它不适用于在运行时计算的参数。

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

The !! !! is two logical "not" operators; 是两个合乎逻辑的“非”运营商; they have the effect of normalizing a value of 0 to 0 , and any non-zero value to 1 . 它们具有将值0归一化为0 ,将任何非零值归一化为1

If the resulting condition is 1 (true), then the value of 1 - 2*!!(condition) is -1 . 如果结果条件为1 (真),则1 - 2*!!(condition)值为-1 If the condition is 0 (false), the value is 1 . 如果条件为0 (假),则值为1

An array may not have a negative (or zero) size. 数组可能没有负(或零)大小。 Some compilers might support zero-length arrays as an extension; 一些编译器可能支持零长度数组作为扩展; this macro ensures that even such a compiler with diagnose an error. 这个宏确保即使是这样的编译器也能诊断出错误。 If the size is a constant expression, an array with a negative size is a constraint violation, requiring a compile-time diagnostic. 如果size是常量表达式,则具有负大小的数组是违反约束的,需要编译时诊断。

If the expression is false, then there's no error; 如果表达式为false,则没有错误; the macro expands to an expression that does nothing. 宏扩展为一个什么都不做的表达式。 If the expression is true and is a constant expression , then the expansion of the macro attempts to define an array of negative size, resulting in a compile-time error. 如果表达式为true 且是常量表达式 ,则宏的扩展尝试定义负大小的数组,从而导致编译时错误。

If the expression is not constant, the macro doesn't work. 如果表达式不是常量,则宏不起作用。 C (C99 and later) permits variable-length arrays (VLAs). C(C99和更高版本)允许可变长度数组 (VLA)。 VLAs of zero or negative length are not permitted, but defining such a VLA cannot in general be detected at compile time. 不允许零或负长度的VLA,但是通常不能在编译时检测到定义这样的VLA。 It is undefined behavior -- and in this case, it's likely to do nothing. 它是未定义的行为 - 在这种情况下,它可能什么都不做。 (Just to complicate things VLAs are not permitted at file scope.) (只是为了使文件范围内不允许使用VLA。)

The macro should, ideally, be accompanied by documentation that explains how to use it. 理想情况下,宏应附有解释如何使用它的文档。 That documentation should explain that the argument must be a compile-time expression. 该文档应该解释该参数必须是编译时表达式。

Bottom line: You should only use this macro with a constant expression argument. 底线:您应该只将此宏与常量表达式参数一起使用。 (To test a run-time expression, you can use assert() .) If you use a non-constant expression with a zero value, the behavior is undefined; (要测试运行时表达式,可以使用assert() 。)如果使用值为零的非常量表达式,则行为未定义; the most likely result is that the intended "assertion" will not fire and the error will not be detected. 最可能的结果是预期的“断言”不会触发,并且不会检测到错误。

I think your method is completely unnatural. 我认为你的方法完全不自然。
It's bad code, even if it would worked. 这是糟糕的代码,即使它会起作用。
You can try more natural approaches to handle errors. 您可以尝试更自然的方法来处理错误。

assert 断言

The macro assert tests for a condition in runtime and shows an error message if the test fails. assert在运行时测试条件,并在测试失败时显示错误消息。

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

static_assert static_assert

In C11 complaint compilers, static_assert(condition, "Error message") does what you want for constant expressions: 在C11投诉编译器中, static_assert(condition, "Error message")执行常量表达式所需的操作:

static_assert((sizeof(struct my_struct) % 8) != 0, "Wrong struct");  

#if and #error #if和#error

Also the #if and #error compiler directives could be used, but I don't advice you in this case, since sizeof is not understood by #if . 也可以使用#if#error编译器指令,但在这种情况下我不建议你,因为#if不理解sizeof

The syntax would be: 语法是:

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

Some of these three methods would have to satisfy your needs. 这三种方法中的一些必须满足您的需求。

Change 更改

BUILD_BUG_ON(cond);

to

BUILD_BUG_ON(1);

to obtain the expected behaviour. 获得预期的行为。

When the cond value is available only in run time then a code that calculates the required sizeof is generated (and its result discarded) in unoptimized builds, or the whole expression is completely ignored in optimized builds. cond值仅在运行时可用时,将在未优化的构建中生成计算所需sizeof的代码(并将其结果丢弃),或者在优化的构建中完全忽略整个表达式。

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

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