Ответ Мехрада должен быть расширен, чтобы он заработал. Также его комментарий
/ * MYVARI (A) BLE здесь не определено * /
не правильно; для проверки неопределенной переменной существует простой тест #ifndef MYVARIABLE
.
Однако после такого теста его выражение приводит к правильному решению исходного вопроса. Я проверял, что этот код работает для неопределенных, определенных, но пустых и непустых значений макроса MYVARIABLE:
#ifndef MYVARIABLE
/* MYVARIABLE is undefined here */
#elif ~(~MYVARIABLE + 0) == 0 && ~(~MYVARIABLE + 1) == 1
/* MYVARIABLE is defined with no value here */
#else
/* MYVARIABLE is defined here */
#endif
Оператор #elif
~(~MYVARIABLE + 0) == 0 && ~(~MYVARIABLE + 1) == 1
работает следующим образом:
- Когда
MYVARIABLE
определено, но пусто, оно расширяется до ~(~+0) == 0 && ~(~+1) == 1
, что дает 0==0 && 1==1
(двойное отрицание ~~ является тождественным оператором).
- Если для
MYVARIABLE
задано числовое значение, скажем, n, оно расширяется до ~(~n+0)==0 && ~(~n+1)==1
. В левой части &&
выражение ~(~n+0)==0
оценивается как n==0
. Но с n==0
правая часть оценивается как ~(~0+1)==1
, с ~ 0, равным -1 до ~(-1+1)==1
, затем ~0==1
и, наконец, -1==1
, что, очевидно, неверно.
- Если для
MYVARIABLE
задано нечисловое значение, прекомпилятор уменьшает все неизвестные символы до 0, и мы получаем предыдущий случай с n == 0 еще раз.
Мой полный тестовый код (сохранить как файл test.c):
#include <stdio.h>
int main() {
printf("MYVARIABLE is "
#ifndef MYVARIABLE
"undefined"
#elif ~(~MYVARIABLE + 0) == 0 && ~(~MYVARIABLE + 1) == 1
"defined without a value"
#else
"defined with this value : %i", MYVARIABLE
#endif
);
printf("\n");
}
С препроцессором GNU cpp вы можете поэкспериментировать, чтобы увидеть, какой код создается:
# undefined
cpp test.c
#defined without a value
cpp -DMYVARIABLE= test.c
#defined wit an implicit value 1
cpp -DMYVARIABLE test.c
#defined wit an explicit value 1
cpp -DMYVARIABLE=1 test.c
#defined wit an explicit value a
cpp -DMYVARIABLE=a test.c
или вывод компиляции и исполнения (под некоторым linux)
$ gcc -o test test.c ; ./test
MYVARIABLE is undefined
$ gcc -DMYVARIABLE= -o test test.c ; ./test
MYVARIABLE is defined without a value
$ gcc -DMYVARIABLE -o test test.c ; ./test
MYVARIABLE is defined with this value : 1
$ gcc -DMYVARIABLE=1 -o test test.c ; ./test
MYVARIABLE is defined with this value : 1
$ gcc -DMYVARIABLE=a -o test test.c ; ./test
test.c: In function ‘main’:
<command-line>:0:12: error: ‘a’ undeclared (first use in this function)
...
В последнем запуске, где MYVARIABLE определен как 'a', ошибка не является ошибкой в определении макроса; макрос корректно приводит к последнему случаю, «определенному с этим значением ...». Но если это значение «a», а «a» не определено в коде, компилятор или курс должны сигнализировать об этом.
Таким образом, последний случай является очень хорошим примером того, почему цель исходного вопроса очень опасна: с помощью макроса пользователь может ввести любую последовательность строк программы в коде, который нужно скомпилировать. Проверка того, что такой код не введен, требует намного больше проверки макроса на допустимые значения. Вероятно, необходим полный сценарий, вместо того, чтобы оставить эту задачу для предварительной обработки. И в таком случае, какой смысл проверять это и в предварительной обработке?