#if sizeof(int) != 4
/* do something */
Использование sizeof внутри #if
не работает, а внутри #define
работает, почему?
#define size(x) sizeof(x)/sizeof(x[0]) /*works*/
#if sizeof(int) != 4
/* do something */
Использование sizeof внутри #if
не работает, а внутри #define
работает, почему?
#define size(x) sizeof(x)/sizeof(x[0]) /*works*/
Ничто не является злом - все может быть неправильно использовано или в вашем случае неправильно понято. Оператор sizeof
является компилятором, но функции компилятора недоступны для препроцессора (который выполняется до того, как компилятор задействован), и поэтому не могут использоваться в директивах препроцессора #if
.
Однако, когда вы говорите:
#define size(x) sizeof(x)/sizeof(x[0])
и используйте его:
size(a)
препроцессор выполняет текстовую подстановку, переданную компилятору:
sizeof(a)/sizeof(a[0])
Препроцессор не может оценить результаты оператора sizeof
. Это вычисляется компилятором, после завершения препроцессора.
Так как второе выражение приводит к вычислению времени компиляции, оно работает. Первый - это невозможный тест для препроцессора.
Короткий ответ представляет собой выражение препроцессора, которое обеспечивает значимую оценку выражения, состоящего из других макросов и констант препроцессора.
Попробуйте это, вы не получите сообщение об ошибке:
#if sizeof < 2
int f(int x) { return x; }
#endif
Если вы создаете сборку, вы обнаружите, что sizeof < 2
компилирует функцию, а sizeof >= 2
- нет. Не возвращает ошибку.
Что происходит? Оказывается, что, за исключением самих макросов препроцессора, все идентификаторы в выражении препроцессора ( "макро" ) заменяются на 0. Таким образом, выше #if
совпадает с:
#if Easter_Bunny < 2
или
#if 0 < 2
Вот почему вы фактически не получаете какую-либо ошибку при ошибочном использовании оператора sizeof
в выражении препроцессора.
Как это бывает, sizeof
является оператором, но он также является идентификатором, а идентификаторы, которые сами по себе не являются макросами, превращаются в 0
в выражениях препроцессора. Препроцессор работает, по крайней мере, концептуально, перед компилятором. Он может превратить синтаксис не C в C, поэтому в момент его запуска программа C еще не была проанализирована. Пока нельзя ссылаться на реальные объекты C: их не существует.
И естественно, sizeof
в заменяющем тексте определения просто передается компилятору, как, ну, заменяющий текст, в котором используется макрос.
#define
- это просто замена текста. #if
- условная препроцессорная директива оценивает sizeof()
, но во время предварительной обработки препроцессор понятия не имеет, что такое sizeof()
. Препроцессор работает до этапа лексического анализа.
sizeof заменяется во время компиляции. Перед запуском компиляции выполняется предварительная обработка.
Компилятор не касается ни одной строки. Скорее, препроцессор копирует файл, заменяя любые экземпляры размера (x) на ваш макрос. Компилятор видит эти замены.
Препроцессор не знает оператора sizeof
, он просто не может его понять. Таким образом, #if
не работает, поскольку он должен понимать, что он работает, потому что это условный условный препроцессор; он должен знать, оценивает ли он значение true или false.
Но #define
не нужно понимать sizeof
, так как #define
предназначен только для замены текста. Препроцессор ищет макрос size
(определенный в #define
) в исходном коде и заменяет его тем, что он определен, который находится в вашем случае sizeof(x)/sizeof(x[0])
.
Причина, по которой он не работает, заключается в том, что макросы предварительного процессора "оцениваются" в проходе до того, как код достигнет компилятора. Поэтому в директиве if-pre-size sizeof (int) (на самом деле sizeof (int)!= 4) нельзя оценить, потому что это выполняется компилятором, а не препроцессором.
Однако оператор определения просто выполняет подстановку текста, и поэтому, когда дело доходит до компилятора, везде, где у вас есть "размер (x)", у вас будет "sizeof (x)/sizeof (x [0])" вместо, а затем это оценивается там на этапе компиляции... в каждой точке кода, где у вас был "размер (x)"
Если вы хотите проверить размер целого числа в процессоре, используйте свою систему make, чтобы узнать размер целого числа в вашей системе перед запуском препроцессора и записать его в файл заголовка, например. #define SIZEOF_INT 4
, включите этот заголовочный файл и сделайте #if SIZEOF_INT == 4
Например, если вы используете cmake, вы можете использовать переменную CMAKE_SIZEOF_INT
, которая имеет размер целого, который вы можете поместить в макрос.