C 2018 6.10.1 имеет дело с условным включением (#if
и связанные с ним операторы и оператор defined
). Пункт 1 гласит:
Выражение, которое управляет условным включением, должно быть выражением целочисленной константы, за исключением того, что: идентификаторы (включая лексически идентичные ключевым словам) интерпретируются, как описано ниже; и может содержать выражения унарного оператора вида
defined
идентификатор
или
defined
(
идентификатор )
…
Целочисленное константное выражение определено в 6.6 6:
целочисленное константное выражение должно иметь целочисленный тип и иметь только операнды, которые являются целочисленными константами, константами перечисления, символьными константами, выражениями sizeof
, результаты которых являются целочисленными константами, выражениями _Alignof
и плавающими константы, которые являются непосредственными операндами приведений. Операторы приведения в выражении с целочисленной константой должны преобразовывать только арифметические типы в целочисленные типы, кроме как как часть операнда, к оператору sizeof
или _Alignof
.
Этот абзац для C обычно, а не только для препроцессора. Таким образом, выражения, которые могут появляться в операторах #if
, совпадают с выражениями целочисленных констант, которые обычно появляются в C. Однако, как указано в приведенной выше цитате, sizeof
и _Alignof
являются просто идентификаторами; они не распознаются как операторы C. В частности, 6.10.1 4 говорит нам:
… После выполнения всех замен в связи с расширением макроса и унарным оператором defined
все оставшиеся идентификаторы (включая лексически идентичные ключевым словам) заменяются на номер pp 0
,…
Итак, где sizeof
или _Alignof
появляются в выражении #if
, оно становится 0
. Таким образом, выражение #if
может иметь только операнды, являющиеся константами, и выражения defined
.
Параграф 4 продолжает:
... Полученные токены составляют выражение управляющей константы, которое оценивается по правилам 6.6. Для целей этого преобразования и оценки токена все целочисленные типы со знаком и все целые типы без знака действуют так, как если бы они имели то же представление, что и типы intmax_t
и uintmax_t
, определенные в заголовке <stdint.h>
.…
6.6 - раздел для константных выражений.
Таким образом, компилятор будет принимать целочисленные суффиксы в выражениях #if
, и это не зависит от реализации C (для суффиксов, требуемых в основном языке C; реализации могут допускать расширения). Однако вся арифметика будет выполняться с использованием intmax_t
или uintmax_t
, и они зависят от реализации. Если ваши выражения не зависят от ширины целых чисел выше требуемого минимума 1 , они должны оцениваться одинаково в любой реализации C.
Кроме того, в параграфе 4 говорится, что могут быть некоторые вариации с символьными константами и значениями, которые я здесь опускаю, поскольку они не относятся к этому вопросу.
Сноска
1 intmax_t
обозначает тип со знаком, способный представлять любое значение любого целочисленного типа со знаком (7.20.1.5 1), а long long int
- это тип со знаком, который должен быть не менее 64 бит ( 5.2.4.2.1 1), поэтому любая соответствующая реализация C должна обеспечивать 64-битную целочисленную арифметику в препроцессоре.