2013-09-25 5 views
11

Есть ли способ написать макрос препроцессора C, который расширяется до разных вещей в зависимости от того, какой аргумент он получает?Можно ли предусмотреть препроцессор в макросе C?

#define foo() ??? 

/* 1 */ 
foo(name) 

/* 2 */ 
foo(_) 

Желаемый результат:

/* 1 */ 
int name; 

/* 2 */ 
/*ignore*/ 

Да, я знаю, что макросы зло. Я прошу об этом в основном из любопытства.

+12

Макросы являются удивительными. –

+2

Не могли бы вы объяснить цель или, может быть, дать лучший пример? Параметр должен быть исправлен во время компиляции, а это значит, что вы можете использовать два разных имени макроса. – lurker

+0

@mbratch: В этом конкретном случае я использую макрос для определения набора переменных, но некоторые переменные являются необязательными, и я хочу избежать их определения. Несколько имен макросов не будут работать хорошо из-за комбинаторного взрыва: с двумя именами переменных мне нужны отдельные макросы для 'foo (a, b)', 'foo (a, _)', 'foo (_, b)' и ' Foo (_, _) '. – hugomg

ответ

8

Возможно, попробуйте несколько многоступенчатого расширения макросов? Это стратегия, используемая Boost preprocessor/control/if library.

#define FOO_NAME 1 
#define FOO__ 2 

#define CONC(a,b) a##_##b 
#define FOO(x) CONC(FOO,x) 

Я не думаю, что есть какой-либо способ проверить условия в рамках расширения макросов C.

Лучшее, что я мог придумать, - это скрыть аргументы макроса строковому литералу с помощью оператора строкой #, а затем проверить использование функций времени выполнения. (Это не будет работать для вашего случая, хотя, где вы хотите, чтобы объявления переменных вывода.)

Например, следующие печатные издания «011»:

#define FOO(x) (strcmp("NAME", #x) ? 1 : 0) 

main() 
{ 
    printf("%d", FOO(NAME)); 
    printf("%d", FOO(1)); 
    printf("%d", FOO(2)); 
} 

Компилятор, вероятно, оптимизировать strcmp сравнения во время компиляции, поэтому он не будет более неэффективным, чем если бы у него были доступные предварительные процессоры. Однако, делая FOO, нормальная функция будет более ясной и, вероятно, такой же эффективной.

+0

Интересный трюк! Но есть ли способ, когда мне не нужно перечислять все возможности для случая «1»? Например, если его '_', то макрос дает 2, если его что-то еще дает 1? – hugomg

+0

Я обновил свой ответ с ограниченным обходным решением, которое не будет работать для вашего первоначального вопроса. –

+0

К сожалению, я не могу использовать тест времени выполнения в моем случае. Я начинаю думать, что первое решение, в котором вы играете, - лучшее, что я смогу получить. – hugomg

8

Чтобы расширить ответ Гэвина Смита, вы на самом деле можете проверить условия в макроподстановкам:

#define FOO_name 1 
#define FOO__ 0 

#define CONC(a,b) a##_##b 

#define IF(c, t, e) CONC(IF, c)(t, e) 
#define IF_0(t, e) e 
#define IF_1(t, e) t 

#define FOO(x) IF(CONC(FOO,x), int x;,) 

FOO(name) // -> int name; 
FOO(_) // -> /*nothing*/ 

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

Как указано выше, это требует, чтобы вы знали все нужные имена заранее.

Смежные вопросы