Как проверить, соответствует ли символ препроцессора # define'd, но не имеет значения?
Используя директивы препроцессора С++, можно ли проверить, был ли определен символ препроцессора, но не имеет значения? Что-то вроде этого:
#define MYVARIABLE
#if !defined(MYVARIABLE) || #MYVARIABLE == ""
... blablabla ...
#endif
EDIT: Причина, по которой я это делаю, заключается в том, что проект, над которым я работаю, должен взять строку из среды через /DMYSTR=$(MYENVSTR)
, и эта строка может быть пустой. Я хочу убедиться, что проект не скомпилируется, если пользователь забыл определить эту строку.
Ответы
Ответ 1
Сома магия:
#define DO_EXPAND(VAL) VAL ## 1
#define EXPAND(VAL) DO_EXPAND(VAL)
#if !defined(MYVARIABLE) || (EXPAND(MYVARIABLE) == 1)
Only here if MYVARIABLE is not defined
OR MYVARIABLE is the empty string
#endif
Обратите внимание, что если вы определяете MYVARIABLE в командной строке, значение по умолчанию равно 1
g++ -DMYVARIABLE <file>
Здесь значение MYVARIABLE равно 1
g++ -DMYVARIABLE= <file>
Здесь значение MYVARIABLE - это пустая строка
Решена проблема цитирования:
#define DO_QUOTE(X) #X
#define QUOTE(X) DO_QUOTE(X)
#define MY_QUOTED_VAR QUOTE(MYVARIABLE)
std::string x = MY_QUOTED_VAR;
std::string p = QUOTE(MYVARIABLE);
Ответ 2
Я хочу убедиться, что проект не скомпилируется, если пользователь забыл определить эту строку.
Пока я проверяю это на предыдущем шаге, вы можете сделать это во время компиляции. Использование Boost для краткости:
#define A "a"
#define B
BOOST_STATIC_ASSERT(sizeof(BOOST_STRINGIZE(A)) > 1); // succeeds
BOOST_STATIC_ASSERT(sizeof(BOOST_STRINGIZE(B)) > 1); // fails
Ответ 3
Я не видел этого решения проблемы, но я удивлен, что это не используется
, Кажется, он работает в Xcode Objc. Различают "определенные без значения" и "определенный набор 0"
#define TRACE
#if defined(TRACE) && (7-TRACE-7 == 14)
#error TRACE is defined with no value
#endif
Ответ 4
Я не думаю, что это можно сделать. При этом я не вижу в этом необходимости. Когда вы делаете символ препроцессора #define
, вы должны установить соглашение, которое вы определяете как 1 или 0 для использования в #if
, или оставьте его пустым.
Ответ 5
Вы можете использовать макрос BOOST_PP_IS_EMPTY
следующим образом:
#include <boost/preprocessor/facilities/is_empty.hpp>
#define MYVARIABLE
#if !defined(MYVARIABLE) || !BOOST_PP_IS_EMPTY(MYVARIABLE)
// ... blablabla ...
#endif
Это трюк для меня. Я добавлю, что этот макрос недокументирован, поэтому используйте его с осторожностью.
Источник: preprocessor-missing-IS-EMPTY-documentation
Ответ 6
Вы не можете, так как препроцессор может проверять только числовое значение. Сравнение строк не покрывается синтаксисом препроцессора.
Ответ 7
Для макросов с целым числом...
Вы можете использовать хак без дополнительных макросов:
#if ~(~MYVARIABLE + 0) == 0 && ~(~MYVARIABLE + 1) == 1
/* MYVARIBLE is undefined here */
#endif
Ответ 8
Ответ Mehrad должен быть расширен, чтобы заставить его работать. Также его комментарий
/* MYVARI (A) BLE undefined здесь */
неверно; для проверки переменной undefined существует простой тест #ifndef MYVARIABLE
.
После такого теста, однако, его выражение приводит к правильному решению исходного вопроса. Я тестировал, что этот код работает, для undefined, определенных, но пустых и непустых значений макроса MYVARIABLE:
#ifndef MYVARIABLE
/* MYVARIABLE is undefined here */
#elif ~(~MYVARIABLE + 0) == 0 && ~(~MYVARIABLE + 1) == 1
/* MYVARIBLE is defined with no value here */
#else
/* MYVARIBLE 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 -DMYVARIALBE= test.c
#defined wit an implicit value 1
cpp -DMYVARIALBE test.c
#defined wit an explicit value 1
cpp -DMYVARIALBE=1 test.c
#defined wit an explicit value a
cpp -DMYVARIALBE=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" не определено в коде, компилятор или курс должны сигнализировать об этом.
Таким образом, последний случай - очень хороший пример того, почему цель оригинального вопроса очень опасна: через макрос пользователь может ввести любую последовательность программных строк в компилируемый код. Проверяя, что такой код не введен, требуется гораздо больше проверки макроса на допустимые значения. Вероятно, требуется полный script, вместо того чтобы оставить эту задачу для предварительной обработки. И в этом случае, что же нужно использовать для предварительной обработки?
Ответ 9
#if MYVARIABLE==0
Мой ответ должен быть не менее 30 символов, чтобы это было сделано!