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
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)
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.
And if it is placed on the same line number in two different files ...
Still, very useful.
@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!
__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.
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'
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
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.
I like it! Thanks!