sizeof () не выполняется препроцессором - PullRequest
15 голосов
/ 21 мая 2011
#if sizeof(int) != 4
/* do something */

Использование sizeof внутри #if не работает, а внутри #define работает, почему?

#define size(x) sizeof(x)/sizeof(x[0]) /*works*/

Ответы [ 9 ]

27 голосов
/ 21 мая 2011

Ничто не является злом - все может быть использовано неправильно или, в вашем случае, неправильно понято.Оператор sizeof является функцией компилятора, но функции компилятора недоступны препроцессору (который запускается до того, как компилятор включается) и поэтому не могут использоваться в директивах препроцессора #if.

Однако, когда вы говорите:

#define size(x) sizeof(x)/sizeof(x[0])

и используете его:

size(a)

препроцессор выполняет текстовое замещение, которое передается компилятору:

sizeof(a)/sizeof(a[0])
5 голосов
/ 23 мая 2011

C Макросы «препроцессора» оценивают только константы и другие макросы

Краткий ответ: выражение препроцессора обеспечивает только значимую оценку выражения, состоящего из других макросов и констант препроцессора.

Попробуйте, вы не получите сообщение об ошибке:

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

5 голосов
/ 21 мая 2011

Препроцессор не может оценить результаты оператора sizeof.Это вычисляется компилятором спустя много времени после завершения препроцессора.

Поскольку второе выражение приводит к вычислению во время компиляции, оно работает.Первый - невозможный тест для препроцессора.

4 голосов
/ 21 мая 2011

#define - просто текстовая замена.#if, будучи условной директивой препроцессора, оценивает sizeof(), но во время предварительной обработки препроцессор понятия не имеет, что такое sizeof().Препроцессор работает до фазы лексического анализа.

3 голосов
/ 21 мая 2011

sizeof заменяется во время компиляции.Предварительная обработка выполняется до начала компиляции.

1 голос
/ 21 мая 2011

Препроцессор не знает оператора sizeof, он просто не может его понять. Так что #if не работает, так как он должен понимать это, чтобы работать, потому что это условный условный препроцессор; ему нужно знать, оценивается ли оно как истинное или ложное.

Но #define не нужно понимать sizeof, так как #define только для замены текста. Препроцессор ищет макрос size (определенный в #define) в исходном коде и заменяет его тем, что определено, как в вашем случае sizeof(x)/sizeof(x[0]).

1 голос
/ 21 мая 2011

Компилятор не касается ни одной строки. Скорее, препроцессор просматривает файл, заменяя все экземпляры размера (x) вашим макросом. Компилятор видит эти замены.

0 голосов
/ 21 мая 2011

Если вы хотите проверить размер целого числа в процессоре, используйте вашу систему make, чтобы узнать размер целого числа в вашей системе перед запуском препроцессора и записать его в файл заголовка, например, #define SIZEOF_INT 4, включите этот заголовокfile and do #if SIZEOF_INT == 4

Например, если вы используете cmake, вы можете использовать переменную CMAKE_SIZEOF_INT, которая имеет размер целого числа, которое вы можете поместить в макрос.

0 голосов
/ 21 мая 2011

Причина, по которой это не работает, заключается в том, что макросы препроцессора «оцениваются» за проход до того, как код достигает компилятора.Таким образом, в директиве пре-процессора if sizeof (int) (фактически sizeof (int)! = 4) не может быть оценен, потому что это делается компилятором, а не препроцессором.

ОпределениеОднако оператор просто выполняет подстановку текста, и поэтому, когда дело доходит до компилятора, везде, где у вас есть «size (x)», вы будете иметь вместо него «sizeof (x) / sizeof (x [0])», и тогда это оцениваеттам на этапе компиляции ... в каждой точке кода, где у вас есть "размер (х)"

...