C Макросы для создания строк - программирование
Подтвердить что ты не робот

C Макросы для создания строк

Альтернативные названия (для поиска)

  • Преобразовать токен препроцессора в строку
  • Как сделать строку char из макроса C?

Оригинальный вопрос

Я хотел бы использовать C #define для построения литеральных строк во время компиляции.

Строка - это домены, которые изменяются для отладки, выпуска и т.д.

Я хотел бы кое-что вроде этого:

#ifdef __TESTING
    #define IV_DOMAIN domain.org            //in house testing
#elif __LIVE_TESTING
    #define IV_DOMAIN test.domain.com       //live testing servers
#else
    #define IV_DOMAIN domain.com            //production
#endif

// Sub-Domain
#define IV_SECURE "secure.IV_DOMAIN"             //secure.domain.org etc
#define IV_MOBILE "m.IV_DOMAIN"

Но препроцессор ничего не оценит в пределах ""

  • Есть ли способ обойти это?
  • Это даже хорошая идея?
4b9b3361

Ответ 1

В C строковые литералы конкатенируются автоматически. Например,

const char * s1 = "foo" "bar";
const char * s2 = "foobar";

s1 и s2 - это одна и та же строка.

Итак, для вашей проблемы ответ (без вставки маркера) -

#ifdef __TESTING
    #define IV_DOMAIN "domain.org"
#elif __LIVE_TESTING
    #define IV_DOMAIN "test.domain.com"
#else
    #define IV_DOMAIN "domain.com"
#endif

#define IV_SECURE "secure." IV_DOMAIN
#define IV_MOBILE "m." IV_DOMAIN

Ответ 2

Есть несколько способов сделать это:

  • Если вы имеете дело только с строковыми литералами, вы можете просто просто использовать строки - размещение одного строкового литерала после другого заставляет компилятор конкатенировать их.

  • если могут быть другие вещи, кроме строковых литералов (т.е. вы создаете новые идентификаторы из макросов), используйте приставку для прокрутки токена "##". Вероятно, вам также необходимо будет использовать '#' ', чтобы сделать ваши макросы в литеральные строки.

Пример # 1:

#ifdef __TESTING
    #define IV_DOMAIN "domain.org"                        //in house testing
#elif __LIVE_TESTING
    #define IV_DOMAIN "test.domain.com"           //live testing servers
#else
    #define IV_DOMAIN "domain.com"                        //production
#endif

// Sub-Domain
#define IV_SECURE "secure." IV_DOMAIN          //secure.domain.org etc
#define IV_MOBILE "m." IV_DOMAIN

И что касается оператора ввода лексем, я не думаю, что большинство ответов, которые предлагали использовать оператор препроцессора, использующего токен, действительно попробовали его - это может быть сложно использовать.

Использование часто используемого ответа приведет к ошибке компилятора при попытке использовать макрос IV_SECURE, потому что:

#define IV_SECURE "secure."##IV_DOMAIN

расширяется до:

"secure"domain.org

Возможно, вы захотите использовать оператор ' # `'' stringising ':

#define IV_SECURE "secure." #IV_DOMAIN

Но это не сработает, потому что оно работает только с макросами, а не с каким-либо старым макросом.

одна вещь, о которой нужно знать, когда вы используете операторы предварительной обработки token-paste ('##') или стробирования ('#'), заключается в том, что вам нужно использовать дополнительный уровень косвенности для правильной работы в все случаи.

Если вы этого не сделаете, и элементы, переданные оператору ввода-вывода, являются самими макросами, вы получите результаты, которые, вероятно, не то, что вы хотите:

#include <stdio.h>

#define STRINGIFY2( x) #x
#define STRINGIFY(x) STRINGIFY2(x)
#define PASTE2( a, b) a##b
#define PASTE( a, b) PASTE2( a, b)

#define BAD_PASTE(x,y) x##y
#define BAD_STRINGIFY(x) #x

#define SOME_MACRO function_name

int main() 
{
    printf( "buggy results:\n");
    printf( "%s\n", STRINGIFY( BAD_PASTE( SOME_MACRO, __LINE__)));
    printf( "%s\n", BAD_STRINGIFY( BAD_PASTE( SOME_MACRO, __LINE__)));
    printf( "%s\n", BAD_STRINGIFY( PASTE( SOME_MACRO, __LINE__)));

    printf( "\n" "desired result:\n");
    printf( "%s\n", STRINGIFY( PASTE( SOME_MACRO, __LINE__)));
}

Выход:

buggy results:
SOME_MACRO__LINE__
BAD_PASTE( SOME_MACRO, __LINE__)
PASTE( SOME_MACRO, __LINE__)

desired result:
function_name21

Таким образом, используя исходные IV_DOMAIN и макросы utilty сверху, вы можете сделать это, чтобы получить то, что вы хотите:

// Sub-Domain
#define IV_SECURE "secure." STRINGIFY( IV_DOMAIN)   //secure.domain.org etc
#define IV_MOBILE "m." STRINGIFY( IV_DOMAIN)

Ответ 3

Строки, которые следуют вместе, объединяются компилятором C.

#define DOMAIN "example.com"
#define SUBDOMAIN "test." DOMAIN
const char *asCString = SUBDOMAIN;
NSString *asNSString = @SUBDOMAIN;

Ответ 4

Попробуйте использовать оператор ##

#define IV_SECURE secure.##IV_DOMAIN

Ответ 5

Я вижу много хороших и правильных ответов на ваш первый вопрос, но ни один на ваш второй, так вот здесь: Я думаю, что это ужасная идея. Почему вам нужно перестроить свое программное обеспечение (в частности, версию выпуска) только для изменения имени сервера? Кроме того, как вы узнаете, какая версия вашего программного обеспечения указывает на какой сервер? Вам нужно будет создать механизм проверки во время выполнения. Если это вообще практично на вашей платформе, я рекомендую вам загрузить домены/URL-адреса из файла конфигурации. Только для самых маленьких встроенных платформ не может быть "практическим" для этой цели:)

Ответ 6

Вам нужны операторы # и ## и автоматическая конкатенация строк.

Оператор # preprocessing превращает макро-параметр в строку. Оператор ## вставляет два токена (например, макропараметры) вместе.

Возможность, которая приходит мне в голову, - это

#define IV_DOMAIN domain.org
#define IV_SECURE(DOMAIN) "secure." #DOMAIN

который должен изменить значение IV_SECURE на

#define IV_SECURE "secure." "domain.org"

который автоматически объединяется с "secure.domain.org" (предполагая, что фазы перевода одинаковы в C как С++).

ДРУГОЕ ИЗМЕНЕНИЕ: Пожалуйста, прочитайте комментарии, которые показывают, как мне удалось запутаться. Имейте в виду, что я очень хорошо знаком с C, хотя, возможно, с ржавым прикосновением. Я бы удалил этот ответ, но я думал, что оставлю его в качестве примера того, как легко запутаться препроцессором C.

Ответ 7

Как отмечали другие, используйте вставку с помощью токена. Вы также должны знать, что имена макросов, такие как

__TESTING

зарезервированы в C (не знаю о Objective C) для реализации - вы не можете использовать их в своем собственном коде. Зарезервированные имена - это все, что содержит двойные подчеркивания и все, что начинается с символа подчеркивания и прописной буквы.