Как сравнить строки в условных препроцессорах C

Я должен сделать что-то подобное в C. Это работает, только если я использую char, но мне нужна строка. Как я могу это сделать?

#define USER "jack" // jack or queen #if USER == "jack" #define USER_VS "queen" #elif USER == "queen" #define USER_VS "jack" #endif 

Я не думаю, что есть способ полностью выполнять сравнения строк длины в директивах препроцессора. Возможно, вы могли бы сделать следующее:

 #define USER_JACK 1 #define USER_QUEEN 2 #define USER USER_JACK #if USER == USER_JACK #define USER_VS USER_QUEEN #elif USER == USER_QUEEN #define USER_VS USER_JACK #endif 

Или вы можете немного реорганизовать код и вместо этого использовать C-код.

[ОБНОВЛЕНИЕ: 2018.05.03]

CAVEAT : Не все компиляторы реализуют спецификацию C ++ 11 таким же образом. Нижеприведенный код работает в компиляторе, на котором я тестировал, в то время как многие комментаторы использовали другой компилятор.

Цитата из ответа Шафика Ягмура на: Вычисление длины строки C во время компиляции. Это действительно констебр?

Постоянные выражения не гарантируются для оценки во время компиляции, у нас есть только ненормативная цитата из стандартного раздела стандарта C ++ 5.19. Константные выражения, которые говорят об этом:

[…]> [Примечание: константные выражения могут быть оценены во время перевода.)

Это слово can все значение в мире.

Итак, YMMV на этом (или любом) ответе, в котором участвует constexpr , в зависимости от интерпретации сценария компилятора спецификации.

[ОБНОВЛЕНО 2016.01.31]

Поскольку некоторым не нравился мой более ранний ответ, потому что он избегал целой compile time string compare аспект OP, достигая цели без необходимости сравнения строк, вот более подробный ответ.

Вы не можете! Не в C98 или C99. Даже в C11. Никакое количество манипуляций MACRO не изменит это.

Определение const-expression используемое в #if , не допускает строк.

Это позволяет использовать символы, поэтому, если вы ограничиваете себя символами, вы можете использовать это:

 #define JACK 'J' #define QUEEN 'Q' #define CHOICE JACK // or QUEEN, your choice #if 'J' == CHOICE #define USER "jack" #define USER_VS "queen" #elif 'Q' == CHOICE #define USER "queen" #define USER_VS "jack" #else #define USER "anonymous1" #define USER_VS "anonymous2" #endif #pragma message "USER IS " USER #pragma message "USER_VS IS " USER_VS 

Ты можешь! В C ++ 11. Если для сравнения используется вспомогательная функция времени компиляции.

 // compares two strings in compile time constant fashion constexpr int c_strcmp( char const* lhs, char const* rhs ) { return (('\0' == lhs[0]) && ('\0' == rhs[0])) ? 0 : (lhs[0] != rhs[0]) ? (lhs[0] - rhs[0]) : c_strcmp( lhs+1, rhs+1 ); } // some compilers may require ((int)lhs[0] - (int)rhs[0]) #define JACK "jack" #define QUEEN "queen" #define USER JACK // or QUEEN, your choice #if 0 == c_strcmp( USER, JACK ) #define USER_VS QUEEN #elif 0 == c_strcmp( USER, QUEEN ) #define USER_VS JACK #else #define USER_VS "unknown" #endif #pragma message "USER IS " USER #pragma message "USER_VS IS " USER_VS 

Таким образом, в конечном итоге вам придется изменить способ реализации вашей цели выбора окончательных значений строк для USER и USER_VS .

Вы не можете сравнивать значения времени компиляции в C99, но вы можете выбирать время для выбора времени.

Если вам действительно нужно выполнить компиляцию сравнений времени, вам нужно перейти на C ++ 11 или более новые варианты, которые позволяют эту функцию.

[ОРИГИНАЛЬНЫЙ ОТВЕТ ПОСЛЕДУЮЩИМ]

Пытаться:

 #define jack_VS queen #define queen_VS jack #define USER jack // jack or queen, your choice #define USER_VS USER##_VS // jack_VS or queen_VS // stringify usage: S(USER) or S(USER_VS) when you need the string form. #define S(U) S_(U) #define S_(U) #U 

ОБНОВЛЕНИЕ: токен ANSI иногда меньше, чем очевидно. ;-D

Помещение единственного # перед макросом приводит к его изменению в строку его значения вместо его голого значения.

Ввод двойного ## между двумя токенами приводит к их объединению в один токен.

Таким образом, макрос USER_VS имеет расширение jack_VS или queen_VS , в зависимости от того, как вы устанавливаете USER .

Стробирующий макрос S(...) использует макроопределение, поэтому значение именованного макроса преобразуется в строку. вместо имени макроса.

Таким образом, USER##_VS становится jack_VS (или queen_VS ), в зависимости от того, как вы устанавливаете USER .

Позже, когда строковый макрос используется как S(USER_VS) значение USER_VS ( jack_VS в этом примере) передается на шаг S_(jack_VS) который преобразует его значение ( queen ) в строку "queen" .

Если вы установите USER для queen то конечным результатом будет строка "jack" .

Для конкатенации токенов см. https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html.

Для преобразования строк токенов см. https://gcc.gnu.org/onlinedocs/cpp/Stringification.html#Stringification

[ОБНОВЛЕНО 2015.02.15, чтобы исправить опечатку.]

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

Наконец, чтобы преобразовать константы JACK или QUEEN в строку, используйте операторы stringize (и / или tokenize).

Следующие работали для меня с clang. Позволяет отображать символическое сравнение макросов. #error xxx – это просто посмотреть, что делает компилятор. Замена определения cat с #define cat (a, b) a ## b ломает вещи.

 #define cat(a,...) cat_impl(a, __VA_ARGS__) #define cat_impl(a,...) a ## __VA_ARGS__ #define xUSER_jack 0 #define xUSER_queen 1 #define USER_VAL cat(xUSER_,USER) #define USER jack // jack or queen #if USER_VAL==xUSER_jack #error USER=jack #define USER_VS "queen" #elif USER_VAL==xUSER_queen #error USER=queen #define USER_VS "jack" #endif 

Как уже было сказано выше, препроцессор ISO-C11 не поддерживает сравнение строк. Однако проблема присвоения макроса с «противоположным значением» может быть решена с помощью «прошивки маркеров» и «доступа к таблице». Простое конкатенация / сжатие макросов Jesse с помощью gcc 5.4.0 не выполняется, потому что строение выполняется до оценки конкатенации (в соответствии с ISO C11). Однако это можно исправить:

 #define P_(user) user ## _VS #define VS(user) P_ (user) #define S(U) S_(U) #define S_(U) #U #define jack_VS queen #define queen_VS jack S (VS (jack)) S (jack) S (VS (queen)) S (queen) #define USER jack // jack or queen, your choice #define USER_VS USER##_VS // jack_VS or queen_VS S (USER) S (USER_VS) 

Первая строка (макрос P_() ) добавляет одно косвенное отношение, чтобы следующая строка (макрос VS() ) завершила конкатенацию перед строкой (см. Почему мне нужен двойной слой косвенности для макросов? ). Макросы строения ( S() и S_() ) принадлежат Джесси.

Таблица (macros jack_VS и queen_VS ), которые намного легче поддерживать, чем конструкция if-then-else OP от Джесси.

Наконец, следующий четырехстрочный блок вызывает macros в стиле функции. Последний четырехстрочный блок из ответа Джесси.

Хранение кода в foo.c и gcc -nostdinc -E foo.c препроцессора gcc -nostdinc -E foo.c дает:

 # 1 "foo.c" # 1 "" # 1 "" # 1 "foo.c" # 9 "foo.c" "queen" "jack" "jack" "queen" "jack" "USER_VS" 

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

Ответ от Патрика и Джесси Чишолма заставил меня сделать следующее:

 #define QUEEN 'Q' #define JACK 'J' #define CHECK_QUEEN(s) (s==QUEEN?1:0) #define CHECK_JACK(s) (s==JACK?1:0) #define USER 'Q' [... later on in code ...] #if CHECK_QUEEN(USER) compile_queen_func(); #elif CHECK_JACK(USER) compile_jack_func(); #elif #error "unknown user" #endif 

Вместо #define USER 'Q' #define USER QUEEN должен также работать, но не был протестирован также работает и может быть проще в обращении.

Если ваши строки являются константами времени компиляции (как в вашем случае), вы можете использовать следующий трюк:

 #define USER_JACK strcmp(USER, "jack") #define USER_QUEEN strcmp(USER, "queen") #if $USER_JACK == 0 #define USER_VS USER_QUEEN #elif USER_QUEEN == 0 #define USER_VS USER_JACK #endif 

Компилятор может заранее сообщить результат strcmp и заменит strcmp своим результатом, тем самым предоставив вам #define, который можно сравнить с директивами препроцессора. Я не знаю, есть ли какая-либо разница между компиляторами / зависимостью от параметров компилятора, но это сработало для меня в GCC 4.7.2.

EDIT: при дальнейших исследованиях, похоже, что это расширение инструментальной цепочки, а не расширение GCC, поэтому учтите это …

Это просто, я думаю, вы можете просто сказать

 #define NAME JACK #if NAME == queen 
Interesting Posts

Указание индекса (не-уникальный ключ) с использованием JPA

Команда FOR / DO дает сообщение «Было неожиданным в это время» при запуске из командной строки

Инструмент для размещения текста на обоях рабочего стола

Различать Chrome из Safari с помощью jQuery.browser

Как определить, относится ли страница документации к Google App Engine к стандартной или гибкой среде

Изменить формат даты на экране блокировки Win 8.1

«Отказано в доступе» при попытке завершить процесс в Windows 8

Событие WebBrowser DocumentCompleted, выпущенное более одного раза

Любые идеи о том, как данные могут быть восстановлены с SSD?

В чем разница между «или» и «|» при программировании в xslt?

CNContactViewController forUnknownContact неприменимо, разрушает интерфейс

Импорт файлов CSV в .Net

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

Кто-то из Microsoft сказал мне, что вы всегда можете уменьшить размер раздела, насколько это возможно, это правда?

ATI Radeon 5770 Eyefinity – три монитора

Давайте будем гением компьютера.