Основываясь на ответах Лундина и Тавиана, общий макрос решения для положительных и отрицательных значений выглядит следующим образом:
#define STATIC_ASSERT_EQUAL(VALUE, EXPECTED) \
(void)_Generic(&(char[(EXPECTED) > 0 ? (VALUE) : (EXPECTED) < 0 ? \
-(VALUE) : (VALUE) == 0 ? 0x7FFFFFFF : (VALUE)]){0}, \
char(*)[(EXPECTED) > 0 ? (EXPECTED) : (EXPECTED) < 0 ? \
-(EXPECTED) : 0x7FFFFFFF] : 0)
Макрос должен использоваться внутри функции.Идея состоит в том, что EXPECTED - это значение, известное программисту, а VALUE - неизвестное вычисленное значение.Это было проверено с GCC 6.1.
Эти проходы без ошибок:
STATIC_ASSERT_EQUAL(-1, -1);
STATIC_ASSERT_EQUAL(0, 0);
STATIC_ASSERT_EQUAL(1, 1);
Однако это также, к сожалению, проходит без ошибок, потому что 0 псевдонимов с 0x7FFFFFFF:
STATIC_ASSERT_EQUAL(0x7FFFFFFF, 0);
Ошибка отображается следующим образом:
STATIC_ASSERT_EQUAL(2, 1);
error: ‘_Generic’ selector of type ‘char (*)[2]’ is not compatible with any association
Если у вас включены определенные предупреждения:
STATIC_ASSERT_EQUAL(0, 1);
error: ISO C forbids zero-size array [-Werror=pedantic]
Поскольку значение EXPECTED не равно 0, программист может принять VALUE == 0.
STATIC_ASSERT_EQUAL(-2, 1);
error: size of unnamed array is negative
В этом случае значение не отображается, но программист может видеть, что ЗНАЧЕНИЕ отрицательно, когда этого не должно быть, поэтому отрицайте ЗНАЧЕНИЕ, и оно отобразится.
STATIC_ASSERT_EQUAL(2, -1);
error: size of unnamed array is negative
Аналогично вышесказанному, программист знает, что ЗНАЧЕНИЕ должно быть отрицательным, но это не так, поэтому отрицание ЗНАЧЕНИЯ заставит его отображаться.
STATIC_ASSERT_EQUAL(-2, -1);
error: ‘_Generic’ selector of type ‘char (*)[2]’ is not compatible with any association
Программист знает, что оно должно быть отрицательным, и здесь он отображает положительный эквивалентVALUE.
STATIC_ASSERT_EQUAL(2, 0);
error: ‘_Generic’ selector of type ‘char (*)[2]’ is not compatible with any association
Вышеуказанный нулевой регистр работает как положено.