Как объединить два строковых макроса в C?

Я пытаюсь реализовать макрос ВЕРСИИ для своей программы, который должен быть изменен при определенных обстоятельствах.

макрос 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

и я понятия не имею, что делать и возможно ли это вообще

Я подозреваю, что самым простым решением является #else #define CD ""- всегда объединять одни и те же макросы, но просто определять их как пустые строки, если они не нужны.

MSalters 24.06.2019 13:16
stackoverflow.com/questions/5256313/…
Sir Jo Black 24.06.2019 13:22

@SirJoBlack Спасибо, я видел этот вопрос, и его решение мне не подходит.

Xtotdam 24.06.2019 13:33

@MSalters Спасибо, это решает первую проблему, но не решает вторую.

Xtotdam 24.06.2019 13:38

Проблема со вторым примером, по-видимому, связана с циклической логикой. VERSION_ определяется с помощью VERSION и VERSION is then defined as VERSION_`. Я даже не понимаю истинного намерения там.

MSalters 24.06.2019 13:55

@MSalters кажется так, я начинаю думать, что макросы C более сложны, чем кажутся. Я использую вашу идею в своем собственном ответе, хотя

Xtotdam 24.06.2019 14:15

@Xtotdam: они, безусловно, сильно отличаются от обычного кода. Если вы посмотрите на C++, он по-прежнему поддерживает макросы для совместимости с C, но C++ стремится разработать лучшие альтернативы для каждого использования макроса.

MSalters 24.06.2019 14:17
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
7
193
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Строковые литералы естественным образом конкатенируют друг с другом

"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 24.06.2019 13:52

@Xtotdam Условно (#if) #undef тогда это? Я не предлагаю вам делать это так просто. Я просто представляю основную технику, которую вы могли бы использовать.

PSkocik 24.06.2019 13:58
Ответ принят как подходящий

Ну, ответ, кажется, следующий:

// 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.

Другие вопросы по теме