LINUX.ORG.RU

gcc дуркует и не может посчитать при компиляции арифметическое выражение из констант

 , ,


1

2

Как известно, в си препроцессор ничего не знает о константах уровня языка, потому, например, проверить условие 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 воспроизводится, а на каких нет.

Deleted

Последнее исправление: Deleted (всего исправлений: 2)

Ответ на: комментарий от Deleted

Пациент путается в показаниях. Добровольно пришел в топик и вступил в диалог, чтобы на ним глумились.

Занятное у вас мозговое заболевание. Как это, смещение или как там...

1.

Иногда бывает нужно, чтобы assert() сработал в compile time

2.

Никакой задачи детектирования сборочного окружения assert не решает и решать не может.

Вы в самом деле не видите тут каши?

vodz ★★★★★
()
Ответ на: комментарий от vodz

Вы в самом деле не видите тут каши?

Не вижу.

Если у меня размер структуры и смещения полей должны соответствовать заданной извне спецификации, я никакой задачи детектировать окружение не решаю. Я просто средствами языка проверяю соответствие реализации и спецификации.

Занятное у вас мозговое заболевание. Как это, смещение или как там...

Ваш кредит на адекватность закончился, добро пожаловать в игнор.

Deleted
()
Ответ на: комментарий от Deleted

Я просто средствами языка проверяю соответствие реализации и спецификации.

Путём отказа в сборке. Адекватность 100%.

Ваш кредит на адекватность закончился, добро пожаловать в игнор

Пф. В отличии от желаемых для вас собеседников я таки продолжу «Добровольно приходить в топик и вступать в диалог», вашими кредитами можете подтереться.

vodz ★★★★★
()

Если в аргумент expr подставляется макрос (INT_MIN), то нужен двойной проход препроцессора в compile_time_assert, для того чтобы макроc в аргументе развернулся раньше чем развернётся compile_time_assert:


#define compile_time_assert(name, expr) \
   compile_time_assert_1(name,expr)

#define compile_time_assert_1(n,e) \
   typedef int compile_time_assert_##n [1 - 2*!(e)]

Но это не спасёт от переполнения знакого целого.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.