# tonfa: 18 Sep 2008
If you want to look at the linux kernel version of that:
http://lxr.linux.no/linux+v2.6.26.5/include/linux/kernel.h#L494
# Pádraig Brady: 18 Sep 2008
cool. So using that method:

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

When that fires it gives:

file.c:16: error: size of array 'type name' is negative

Whereas the one on the web page gives:

file.c:16: warning: division by zero
file.c:16: error: enumerator value for 'assert_line_16' is not an integer constant
# kL: 18 Sep 2008
Take a look at D programming language - it has static asserts and even unit testing at language level (and it's as fast and low-level as C)
# Keith Thompson: 18 Sep 2008
The trick of enclosing the enum definition in braces:

#define ct_assert(e) {enum { ct_assert_value = 1/(!!(e)) };}

is a good one, but it's still not completely general. Without the braces, it's a declaration; with the braces, it's a statement, specifically a compound statement.

C99 (which is not widely implemented) allows declarations and statements to be mixed, so the braces aren't necessary if you're using a C99 compiler, or a C++ compiler, or a pre-C99 compiler that allows mixed declarations and statements as an extension.

But in strict C90, all declarations in a block must be followed by all statements in a block; they can't be mixed. So if the version with the braces is used within the declaration part of a block (specifically, if it's followed by a declaration at the same level), then it's an error.

A workaround is to define two versions of the macro, one without the braces for use in a declaration context, and another with the braces for use in a statement context.
# Bill davy: 14 Oct 2008
And if it is placed on the same line number in two different files ...

Still, very useful.
# Pádraig Brady: 14 Oct 2008
@Bill good point.

If these files are in the same compilation unit you'll get an error. For e.g. you could hit this if you had multiple header files using ct_assert() on the same line, as confirmed by:

echo "enum { a = 1 }; enum { a = 1 };" | gcc -xc -

I'll look at putting __FILE__ or some other distinguishing id in there.

thanks!
# Bill Davy: 16 Oct 2008
__COUNTER__ on VS could help but even that does not guarantee uniqueness as it always starts in the same place after a pre-compiled header.
# Bill Davy: 20 Oct 2008
Think I'll stick with the old one. VS gets too excited!

d:\work\dmm1_0\fe_dhs\devapp\dmm11\shareddata.h(32) : error C2148: total size of array must not exceed 0x7fffffff bytes
d:\work\dmm1_0\fe_dhs\devapp\dmm11\shareddata.h(32) : error C2148: total size of array must not exceed 0x7fffffff bytes
d:\work\dmm1_0\fe_dhs\devapp\dmm11\shareddata.h(32) : error C2070: 'char [-1]': illegal sizeof operand
d:\work\dmm1_0\fe_dhs\devapp\dmm11\shareddata.h(32) : error C2466: cannot allocate an array of constant size 0
d:\work\dmm1_0\fe_dhs\devapp\dmm11\shareddata.h(55) : error C2556: 'char (*ct_assert(void))[1]' : overloaded function differs only by return type from 'char (*ct_assert(void))[]'
d:\work\dmm1_0\fe_dhs\devapp\dmm11\shareddata.h(32) : see declaration of 'ct_assert'
d:\work\dmm1_0\fe_dhs\devapp\dmm11\shareddata.h(55) : error C2369: 'ct_assert' : redefinition; different subscripts
d:\work\dmm1_0\fe_dhs\devapp\dmm11\shareddata.h(32) : see declaration of 'ct_assert'
d:\work\dmm1_0\fe_dhs\devapp\dmm11\shareddata.h(227) : error C2556: 'char (*ct_assert(void))[1]' : overloaded function differs only by return type from 'char (*ct_assert(void))[]'
d:\work\dmm1_0\fe_dhs\devapp\dmm11\shareddata.h(32) : see declaration of 'ct_assert'
d:\work\dmm1_0\fe_dhs\devapp\dmm11\shareddata.h(341) : error C2556: 'char (*ct_assert(void))[1]' : overloaded function differs only by return type from 'char (*ct_assert(void))[]'
d:\work\dmm1_0\fe_dhs\devapp\dmm11\shareddata.h(32) : see declaration of 'ct_assert'
d:\work\dmm1_0\fe_dhs\devapp\dmm11\stdafx.h(205) : error C2556: 'char (*ct_assert(void))[1]' : overloaded function differs only by return type from 'char (*ct_assert(void))[]'
d:\work\dmm1_0\fe_dhs\devapp\dmm11\shareddata.h(32) : see declaration of 'ct_assert'
# Jesse Chisholm: 07 Apr 2009
In the Microsoft compiler (VS.2008) the expression (1/!!(e)) generates a warning. It must implicitly cast bool to int. An alternate expression, that is only slightly uglier is (1/((e)?1:0)) which has the same effect, but removes the implicit cast.

-Jesse
# Pádraig Brady: 07 Apr 2009
Argh! Thanks Jesse. So it's giving a warning about dividing an int with a bool? Could I add a cast instead? I'm wary about adding conditionals.
# Brent: 08 Nov 2011
I like it! Thanks!
# stephen.pitts3@gmail.com: 08 Nov 2012
Adding a statc assert of the non-C11 style immediately after a case statement causes an erro (cannot use label.....) in CCS5.
Consequently the macro requires an extra brace at the start and a semi colon and brace at the end.
# Pádraig Brady: 08 Nov 2012
Updated. Thanks!
# serhio: 17 Oct 2013
What about next macro:

/*
* Simple compile time assertion.
* Example: CT_ASSERT(sizeof foo <= 16, foo_can_not_exceed_16_bytes);
*/
#define CT_ASSERT(exp, message_identifier) \
struct compile_time_assertion { \
char message_identifier : 8 + !(exp); \
}

For example in comment MSVC tells something like:

test.c(42) : error C2034: 'foo_can_not_exceed_16_bytes' : type of bit field too small for number of bits
Name:
Website:
comments:
(no HTML)
31+7