Я пытаюсь реализовать макрос ВЕРСИИ для своей программы, который должен быть изменен при определенных обстоятельствах.
макрос VERSION определяется через Makefile (туда помещается информация git) и представляет собой строку. Теперь у меня есть набор переключателей #define, и я хочу, чтобы ВЕРСИЯ отражала, какие из них включены. Теперь это выглядит следующим образом (main.h):
#define COMPLEX_DEPOSITION // This is switch. later in code it is used in #ifdef...#endif construction.
#ifdef COMPLEX_DEPOSITION
#define CD "_COMP_DEP" // this is the string I want to put in the end of VERSION
#define VERSION_ VERSION CD
#undef VERSION // this is to suppress 'macro redefinition' warning
#define VERSION VERSION_
#undef VERSION_
#endif
Ну, я получаю много ошибок, большинство из которых заставляют меня думать, что препроцессор C работает со строками в файле в случайном порядке :(
Позже у меня есть еще более сложная вещь, которую я намереваюсь сделать VERSION -> VERSION_WLT_GAP_2
#define WIRESLIFETIMES
#ifdef WIRESLIFETIMES
#define GAP 2
#define VERSION_ (VERSION ## "_WLT_GAP_" ## #GAP)
#define VERSION VERSION_
#undef VERSION_
#endif
и я понятия не имею, что делать и возможно ли это вообще
@SirJoBlack Спасибо, я видел этот вопрос, и его решение мне не подходит.
@MSalters Спасибо, это решает первую проблему, но не решает вторую.
Проблема со вторым примером, по-видимому, связана с циклической логикой. VERSION_
определяется с помощью VERSION
и VERSION is then defined as
VERSION_`. Я даже не понимаю истинного намерения там.
@MSalters кажется так, я начинаю думать, что макросы C более сложны, чем кажутся. Я использую вашу идею в своем собственном ответе, хотя
@Xtotdam: они, безусловно, сильно отличаются от обычного кода. Если вы посмотрите на C++, он по-прежнему поддерживает макросы для совместимости с C, но C++ стремится разработать лучшие альтернативы для каждого использования макроса.
Строковые литералы естественным образом конкатенируют друг с другом
"foo" "bar"
то же, что "foobar"
.
Что касается второго примера, вы, вероятно, захотите:
#define CAT_(A,B) A##B
#define CAT(A,B) CAT_(A,B)
#define GAP 2
#define VERSION CAT(VERSION_WLT_GAP_ , GAP)
VERSION //expands to VERSION_WLT_GAP_2
Я рекомендую немного поиграть с gcc -E
/clang -E
, чтобы узнать, как работают макросы,
прежде чем пытаться составить что-то сложное с ними.
Спасибо, но дело в том, что макрос VERSION содержит значение, полученное из Makefile.
@Xtotdam Условно (#if
) #undef
тогда это? Я не предлагаю вам делать это так просто. Я просто представляю основную технику, которую вы могли бы использовать.
Ну, ответ, кажется, следующий:
// https://stackoverflow.com/questions/5256313/c-c-macro-string-concatenation
// Concatenate preprocessor tokens A and B without expanding macro definitions (however, if invoked from a macro, macro arguments are expanded).
#define PPCAT_NX(A, B) A ## B
// Concatenate preprocessor tokens A and B after macro-expanding them.
#define PPCAT(A, B) PPCAT_NX(A, B)
// Turn A into a string literal without expanding macro definitions (however, if invoked from a macro, macro arguments are expanded).
#define STRINGIZE_NX(A) #A
// Turn A into a string literal after macro-expanding it.
#define STR(A) STRINGIZE_NX(A)
#define COMPLEX_DEPOSITION
#ifdef COMPLEX_DEPOSITION
#define CD "_COMPDEP"
#else
#define CD ""
#endif
#define WIRESLIFETIMES
#ifdef WIRESLIFETIMES
#define GAP 2
#define WLT STR(PPCAT(_WLT:G, GAP))
#define DISABLE_METROPOLIS
#else
#define WLT ""
#endif
#define VERSION VERSIONX CD WLT
который производит V008.1-11-g68a9c89cb4-dirty_COMPDEP_WLT:G2
и я доволен этим.
Следует отметить, что я изменил -DVERSION=...
на -DVERSIONX=...
внутри Makefile.
Я подозреваю, что самым простым решением является
#else #define CD ""
- всегда объединять одни и те же макросы, но просто определять их как пустые строки, если они не нужны.