Как известно, в си препроцессор ничего не знает о константах уровня языка, потому, например, проверить условие sizeof(что-нибудь) > 8
при помощи #if
не получится.
Чтобы делать compile time assert в си, есть вот такой прикол:
#define compile_time_assert(name, expr) \
typedef int compile_time_assert_## name [1 - 2*!(expr)]
Эта штука не даёт коду скомпилироваться, если выражение expr вычислилось в 0 или если оно не может быть вычислено на этапе компиляции.
Например:
compile_time_assert(test1, 1);
compile_time_assert(test2, 2);
compile_time_assert(test3, 3);
compile_time_assert(test4, 4);
compile_time_assert(test5, 5);
compile_time_assert(test6, -1);
compile_time_assert(test7, -2);
compile_time_assert(test8, 10 == 10);
/* should fail, if uncommented: */
/* compile_time_assert(should_fail, 0); */
compile_time_assert(ancient_compiler_shall_not_pass, sizeof(int) >= 4);
----------------------------------------------
Это было вступление. Теперь, собственно, баг:
compile_time_assert(twos_complement_math, INT_MIN == -INT_MIN);
Компилируется в tcc (0.9.27) и clang (7.0.0). В gcc (8.2.1) не компилируется. Компилятор считает, что выражение не может быть вычислено на этапе компиляции. (И это при том, что в предыдущем warning-е он уже его вычислил.) Вот что получается:
4.c:19:54: warning: integer overflow in expression '-2147483648' of type 'int' results in '-2147483648' [-Woverflow]
compile_time_assert(twos_complement_math, INT_MIN == -INT_MIN);
^
4.c:5:51: note: in definition of macro 'compile_time_assert'
typedef int compile_time_assert_## name [1 - 2*!(expr)]
^~~~
4.c:5:14: error: variably modified 'compile_time_assert_twos_complement_math' at file scope
typedef int compile_time_assert_## name [1 - 2*!(expr)]
^~~~~~~~~~~~~~~~~~~~
4.c:19:1: note: in expansion of macro 'compile_time_assert'
compile_time_assert(twos_complement_math, INT_MIN == -INT_MIN);
Это я что-то делаю не так, или это баг?
Потестируйте у себя, на каких версиях gcc воспроизводится, а на каких нет.