Checking sizeof at compile time
Sometimes you may have some C code which contains a struct which has some constraints on its size. For example, maybe the struct has to be aligned on certain byte boundaries due to hardware constraints (maybe it’s a DMA buffer to some device which uses lower bits of the address for its own purposes), and you need an array of such structs, and for each member of the array to be properly aligned, the size of the struct must be a multiple of, say, 8.
You might be tempted to try something like:
#if ((sizeof(struct mystruct) % 8 ) != 0) #error "you screwed up struct mystruct again!" #endif
which won’t work for a number of reasons, one of which is probably that I’ve botched the preprocessor syntax, but most importantly it won’t work because the preprocessor has no idea about C types, and thus no idea what sizeof is.
So, you may have settled for some runtime code to do:
if ((sizeof(struct mystruct) % 8 ) != 0) { printf("You screwed up mystruct again!\n"); exit(1); }
But this is less than satisfactory, because you don’t catch the problem until runtime.
Is there a way to catch this kind of thing at compile time? Yes there is. I came across this in the linux kernel, in include/linux/kernel.h:
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
With that bit of black magic, you can then put this in your code:
{ /* check that you didn't screw up mystruct */ BUILD_BUG_ON(sizeof(struct mystruct) % 8)); }
This will fail to compile if sizeof(struct mystruct) is not a multiple of 8. If struct mystruct is a multiple of 8, it will insert no runtime code at all.
Cool.
But, wtf is it doing? How does it work?
It relies on a few tricks. It may help to think about what any such macro must do. We want a macro that evaluates an expression. If the expression is true, the macro must compile without warnings, and produce no code at all. When the expression is false, it must not compile.
So we need some kind of statement which doesn’t compile depending on the value of a number. Some genius had the brilliant idea that an array with a negative size won’t compile, but will compile with a size of 1 or greater (even a zero sized array is legal nowadays.)
char myarray[1]; /* this will compile. */ char myarray2[-1]; /* this will not compile */
But, we don’t actually want to declare an array, so it is put in terms of a type being measured by sizeof.
sizeof(char[1]); /* this gives you the size of a */ /* character array of 1. */ sizeof(char[-11]); /* this doesn't compile */
And how to get this into a form which generates zero code when it compiles? Well, it so happens that a bare expression is a valid statement in C. So this:
1; /* this is a legal C statement with no effect. */
is a legal C statement with no effect. Well, almost no effect. It has the effect that gcc -Wall will complain:
warning: statement with no effect
That’s what the “(void)” is for.
(void) 1;
is a valid C statement with no effect, not even a warning from gcc -Wall.
So, what about the ‘!!’ in the expression “sizeof(char[1 – 2*!!(condition)]”? Near as I can tell, that is converting all non-zero values into the value 1.
So, if the argument to BUILD_BUG_ON is non zero, the macro evaluates to:
(void) sizeof(char[-1]);
which fails to compile, which is what we want. and if the value of the argument to BUILD_BUG_ON is zero, then the macro evaluates to:
(void) sizeof(char[1]);
which compiles with no warnings, and produces no code.
Pretty slick.
[…] code was in a kernel driver, and I knew the size of the structure was incorrect (as there was some some magic macros watching my back. I knew that the consequence of this being wrong was that the kernel would panic […]
An interesting way to find the size of a structure in C « Scary Reasoner said this on July 2, 2009 at 4:42 am |
[…] actually did have a BUILD_BUG_ON in the code that is designed to catch precisely this problem at build time, but somehow in a patch, […]
Fixed a very hard bug at work today. « Scary Reasoner said this on January 22, 2010 at 3:53 am |
This is ingenious! This is what I need!
tester said this on September 26, 2013 at 9:19 am |
!! is not a special operator; it’s just an application of the logical not operator ! twice. A single ! yields to one if the value is zero and zero otherwise, a second ! negates the result thus yielding to zero if the original value was zero and to one otherwise; which is what it is all about.
anonymous said this on February 28, 2014 at 11:41 am |
It doesn’t work to me, no error is raised while compiling (gcc and g++).
Cristiano Cenci said this on August 1, 2014 at 6:57 pm |
[…] Courtesy: https://scaryreasoner.wordpress.com/2009/02/28/checking-sizeof-at-compile-time/ […]
Adding preprocessor checks, Checking sizeof at compile time | Wintergreen Works said this on January 21, 2015 at 7:28 am |
Hi, this was a life-saver, and a great trick! Ultimately, though, it didn’t work for me at global (definition) scope level, because you can only declare and define things, and not execute C statements.
However it saved the day because I was able to adapt it:
#define MACRO_ASSERT(condition,message) extern int macro_assert[!!(condition)-1]
This pre-processes to an external declaration (a zero-sized array named’ macro_assert’), which is a legal line both within a function, and in the global context.
Thank you very much for sharing the tip!
Stuart
Stuart Woodard said this on April 25, 2015 at 11:47 am |
it works for me .. thanks a lot .. it is useful blog
Nirav said this on August 27, 2015 at 9:26 pm |
Brilliant! I was just trying to get a compile-time error if sizeof(int)!=4
Long story short, this showed how.
brucemardle said this on July 30, 2017 at 10:10 pm |
Thank you so much for this bit of black magic!
Qudos to the people that come up with these 🙂
You can shorten this to a more sensible:
#define COMPILER_ASSERT(condition) ((void)sizeof(char[-!(condition)]))
Jay said this on June 10, 2019 at 1:04 am |