Можно ли предусмотреть препроцессор в макросе C?

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

#define foo() ???

/* 1 */
foo(name)

/* 2 */
foo(_)

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

/* 1 */
int name;

/* 2 */
/*ignore*/

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

Ответ 1

Возможно, попробуйте несколько многоэтапных расширений макросов? Это стратегия, используемая 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, нормальная функция будет более ясной и, вероятно, такой же эффективной.

Ответ 2

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

#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, чтобы разрешить запятые, подавить макрообъем и т.д. с помощью вспомогательных макросов.

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