Как я могу получить препроцессор gcc, чтобы проверить, оценивает ли выражение значение или ничего?

Я использую gcc (в частности avr-gcc).

Итак, это моя головоломка:

Скажем, я определил где-то это:

#define THING_0_A 0
#define THING_0_B 1
#define THING_1_A 0

Затем во втором файле у меня есть:

#define CONCAT_(A,B,C) A ## B ## C
#define CONCAT(A,B,C) CONCAT_(A,B,C)

#define ID 0

#define THING_N(A) CONCAT(THING_,ID,A)

С этим теперь у меня есть выбор выражений (все еще во втором файле):

THING_N(_A) // evaluates to 0
THING_N(_B) // evaluates to 1
THING_N(_C) // evaluates to... nothing? Or undefined? Or THING_0_C?

Теперь, что я пытаюсь решить, как это сделать (также все еще во втором файле):

#ifdef THING_N(_A)
    // Do something knowing that THING_N(_A) is defined (in this case THING_0_A)
#endif

Или:

#if THING_N(_A)
    // Do something knowing that the value THING_N(_A) evaluates to is defined and not just "nothing"
#endif

Конечно, ни одна из них не работает, потому что #ifdef не может принимать выражение в качестве аргумента (и в любом случае оно будет равно "#ifdef 0" ), а THING_N (_A) оценивается 0 в #if.

Другими словами, я ищу способ оценить препроцессор:

THING_N(_A) to true
THING_N(_B) to true
THING_N(_C) to false
THING_N(_D) to false
etc...

который будет использоваться в условном выражении.

Ответ 1

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

Учитывая настройку, которую я задал в своем вопросе, это выражение выражается так:

THING_N(_A) -> THING_0_A -> 0
THING_N(_B) -> THING_0_B -> 1
THING_N(_C) -> THING_0_C -> 0 (Not nothing, as I previously thought.)

Часть информации, которую я раньше отсутствовала, заключалась в том, что, согласно стандарту c99, идентификаторы undefined будут преобразованы в 0, а не ничего, что делает невозможным различать что-то undefined и то, что определено как 0.

Если бы стандарт c99, выбранный для того, чтобы идентификаторы undefined не оценивались ни в чем, так же, как #define FOO делает FOO ничего не оцененным, тогда решение atturri сработало бы.

Ну ладно.

Ответ 2

Попробуйте следующее:

#if (1-THING_N(_A)-1 != 2)

Это будет true для каждого значения THING_N(_A) (за исключением значения -2). Это будет false, только если THING_N(_A) равно undefined или определено пустым.

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

Ответ 3

Вы можете связать значение с известным значением и проверить результат:

#define EMPTY_VAL_HELPER(VAL)  VAL ## 1
#define EMPTY_VAL(VAL)         EMPTY_VAL_HELPER(VAL)

Теперь вы можете сделать:

#if defined(FOO) && (EMPTY_VAL(FOO) == 1)
//FOO is defined, but empty
#endif

#if defined(FOO) && (EMPTY_VAL(FOO) != 1)
//FOO is defined, and not empty
#endif