Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Different behaviour of C macro for different cases

Tags:

c

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. 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?

like image 595
Jagdish Avatar asked Jul 18 '15 18:07

Jagdish


1 Answers

The BUILD_BUG_ON macro is intended to implement a compile-time assertion.

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).

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.

If the resulting condition is 1 (true), then the value of 1 - 2*!!(condition) is -1. If the condition is 0 (false), the value is 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.

If the expression is false, then there's no error; 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.

If the expression is not constant, the macro doesn't work. C (C99 and later) permits variable-length arrays (VLAs). VLAs of zero or negative length are not permitted, but defining such a VLA cannot in general be detected at compile time. 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.)

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; the most likely result is that the intended "assertion" will not fire and the error will not be detected.

like image 139
Keith Thompson Avatar answered Sep 27 '22 01:09

Keith Thompson