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

альтернативные названия (to aid search)

  • преобразование токена препроцессора в строку
  • как сделать строку символов из 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"

но препроцессор ничего не оценивает в ""

  1. есть ли способ обойти это?
  2. это вообще хорошая идея?

7 ответов


в 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

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

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

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

Пример #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

вы можете попробовать использовать '#` оператор 'stringizing':

#define IV_SECURE "secure." #IV_DOMAIN

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

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

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

#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 определяет и утилитарные макросы сверху, вы можете сделать это, чтобы получить то, что вы хотите:

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

строки, следующие друг за другом, объединяются компилятором C.

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

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


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

#define IV_SECURE secure.##IV_DOMAIN

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

оператор # 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, хотя, возможно, немного ржавый. Я бы удалил этот ответ, но я думал, что оставлю его в качестве примера того, как легко запутаться в препроцессоре C.


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

__TESTING

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