Функциональное определение макроса в C

Я хотел бы определить такую ​​функцию, как MACRO. т.е.

#define foo(x)\ #if x>32\ x\ #else\ (2*x)\ #endif 

то есть,

 if x>32, then foo(x) present x else, foo(x) present (2*x) 

но мой GCC жалуется:

 int a = foo(31); 

Я думаю, что препроцессор C должен справиться с этим правильно. так как во время компиляции он знает x=33 . он мог бы заменить foo(33) на (2*33)

Вы можете следующим образом

 #define foo(x) ((x) > 32 ? (x) : (2 * (x))) 

Но это оценивает x несколько раз. Вместо этого вы можете создать статическую функцию, которая является более чистой

 static int foo(int x) { if(x > 32) return x; return 2 * x; } 

Затем вы также можете передавать вещи в foo которые имеют побочные эффекты, и побочный эффект происходит только один раз.

То, что вы написали, использует #if , #else и #endif preprocessor, но вам нужно использовать языковые конструкции, если вы передаете переменные макросу и хотите оценить их значения. Использование операторов if и else как в реальных конструкциях языка, также не работает, потому что операторы streamа управления не оценивают значения. Другими словами, оператор if является только streamом управления рулевым управлением («если A, а затем выполнить B, иначе выполняйте C»), не оценивая никаких значений.

 #define \ foo(x) \ ({ \ int xx = (x); \ int result = (xx > 32) ? xx : (2*xx); \ result; \ }) 

Рассматривать:

 int x = rand() int y = foo( x ); 

x не известно во время компиляции.

 int a = foo(31); 

Расширяется до

 int a = if 31>32 31 else (2*31) endif; 

Вот как работают macros C с помощью простой, немой подстановки. Если вы ожидаете, что gcc сделает с ними что-нибудь более сложное или интеллектуальное, ваше ожидание ошибочно.

Учитывая это, легко понять, почему ваш код не будет работать. Альтернативой, достаточной для этого примера, будет:

 #define foo(x) (x > 32 ? x : 2*x) 

С другой стороны, я бы поставил под вопрос, являются ли macros действительно подходящим инструментом для такого начала. Просто поместите его в функцию, и компилятор включит код, если он подумает, что он ускорит его.

Проблема не в теории: если вы по какой-то причине хотите иметь макрос, который расширяется по-разному в соответствии со значением переданного ему параметра, и этот параметр является константой, известной препроцессору макросов, нет причина, почему он не может работать … для общего макропроцессора … Но cpp не повезло, не позволяет присутствию других «команд» макропроцессора в определении макроса …

Так что ваши

 #define foo(x) \ #if x>32 \ x \ #else \ 2*x \ #endif 

не расширяется до

 #if X>32 X #else 2*X #endif 

где X – известный параметр (так что измените X на 31), что требует другого прохода препроцессором.

Более того, символы новой строки игнорируются, хотя они важны для такого использования; в противном случае следующее можно было бы рассматривать как трюк (для этого требуется другой проход предварительной обработки)

 #define foo(x,y) \ y if x>32 \ x \ y else \ 2*x \ y endif 

что при foo(20,#) получается

 # if 20>32 20 # else 2*20 # endif 

который будет работать, если бы это было

 # if 20>32 20 # else 2*20 # endif 

… но это не так (и, как сказано, выход препроцессора должен быть снова подан на препроцессор …)

Поэтому я отвечаю, что если вам нужны эти вещи, вы не можете использовать препроцессор C; вы должны использовать необычный (не стандартный?) C-препроцессор или просто другой макропроцессор, и если вам нужны такие вещи, которые «cpp» должен «интегрировать» с C, то вы не можете использовать общий ( как M4) так легко …