Функциональное определение макроса в C - PullRequest
6 голосов
/ 09 июля 2010

Я бы хотел определить функцию, подобную 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)

Ответы [ 5 ]

12 голосов
/ 09 июля 2010

Вы можете сделать следующее

#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, но вам нужно использовать языковые конструкции, если вы передаете переменные в макрос и хотите оценить их значения.Использование операторов if и else, как в реальных языковых конструкциях, также не работает, поскольку операторы потока управления не оцениваются в значения.Другими словами, оператор if управляет только потоком управления («если A, затем выполнить B, иначе выполнить C»), не вычисляя ни одно из значений.

7 голосов
/ 10 июля 2010
#define \
    foo(x) \
    ({ \
        int xx = (x); \
        int result = (xx > 32) ? xx : (2*xx); \
        result; \
    })
2 голосов
/ 09 июля 2010
int a = foo(31);

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

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

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

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

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

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

2 голосов
/ 09 июля 2010

Рассмотрим:

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

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

1 голос
/ 09 июля 2010

Проблема не в теории: при условии, что вы по какой-то причине хотите иметь макрос, который расширяется по-разному в зависимости от значения переданного ему параметра, и этот параметр является константой, известной препроцессору макроса нет никаких причин, по которым это не могло бы работать ... для универсального макропроцессора ... Но 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) так легко ...

...