This is your typical smelly old *nix bugware.
- Problem 1) The macro
BUILD_BUG_ON_ZERO causes a compiler error in case the expression is not zero. So the name is already very confusing.
What the code does:
Essentially this is a pre-C11 static assert. Other answers have mostly explained what the code does. It attempts to declare a bit-field. There's a constraint in ISO C23 6.7.3.2:
The expression that specifies the width of a bit-field shall be an integer constant expression with a nonnegative value that does not exceed the width of an object of the type that would be specified were the colon and expression omitted. If the value is zero, the declaration shall have no declarator.
As we can tell from the above, the bit-field size may not be non-negative. Specifically, a bit-field with size zero means the end of a previous bit-field:
As a special case, a bit-field structure member with a width of zero indicates that no further bit-field is to be packed into the unit in which the previous bit-field, if any, was placed.
!! turns any expression into a boolean one of type int, so we end up with either 0 or 1, which is a signed temporary value.
-1 would violate the previously quoted constraint of declaring negative bit-fields. So far it all seems good. However...
The gcc compiler helpfully lets you know of this severe bug if you compile with -pedantic.
Now GNU C does explicitly allow a struct with no members as a language extension. However this isn't really the case here: we do have a member but it has no name. The gcc manual doesn't cover the case as a valid extension, so the behavior of the code is both undefined and undocumented. Taking the size of such a struct does not appear to be well-defined either.
So the macro essentially introduces yet another bug in the code no matter the outcome.
Better written, well-defined code would have been struct { int dummy:1; int:-!!(e); }, however that will return a non-zero size. Alternatively struct { int:-!!(e); int dummy[]; } should return size zero.
How to fix?
_Static_assert or static_assert is the obvious choice. C programmers are expected to know of these language features, so the whole BUILD_BUG_ON_ZERO macro is obsolescent since quite a while back.
Static asserts are declarations, so they may be present inside struct/union declarations. If you want it to also generate some sort of dummy value in case the assertion passed, that can be done like this:
#define STATIC_ASSERT_PLUS(expr) ( (struct { int val; static_assert((expr), "optional error message"); }){0}.val )
This creates a compound literal containing an unnamed struct, which is initialized to zero. It has the reverse/corrected logic of BUILD_BUG_ON_ZERO so this macro will create a compiler error on zero. In this case it returns value 0 of type int but it can easily be modified to use another type or value. This code is pure ISO C (C11 or later).
sizeofdoes "evaluate" the type, just not the value. Its the type thats invalid in this case.:0gives a zero-sized anonymous bit-field, and therefore a zero-sized struct. That's not quite true; in standard C,:0is not any kind of field declaration (you can't give it a name) but rather a directive to start the next bit-field on the next word boundary (typicallyintbut not necessarily). It doesn't normally have any significance unless used between two (otherwise adjacent) bit-field declarations. The resulting struct is zero-sized because it contains no declarations; and that of course is a gcc extension.