C宏来创建字符串

rjs*_*ing 30 c macros stringification c-preprocessor

替代标题(以帮助搜索)

  • 将预处理程序标记转换为字符串
  • 如何从C宏的值创建一个char字符串?

原始问题

我想在编译时使用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"
Run Code Online (Sandbox Code Playgroud)

但预处理器不评估""内的任何内容

  1. 有没有解决的办法?
  2. 这甚至是个好主意吗?

Ale*_*x B 38

在C中,字符串文字自动连接.例如,

const char * s1 = "foo" "bar";
const char * s2 = "foobar";
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)


Mic*_*urr 27

有几种方法可以做到这一点:

  1. 如果你只处理字符串文字,你可以简单地使用简单地使用字符串 - 将一个字符串文字放在另一个之后会导致编译器连接它们.

  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
Run Code Online (Sandbox Code Playgroud)

就令牌粘贴操作符而言,我认为使用令牌粘贴预处理器操作符的大多数答案都没有实际尝试过 - 使用起来可能很棘手.

使用通常建议的答案会在您尝试使用IV_SECURE宏时导致编译器错误,因为:

#define IV_SECURE "secure."##IV_DOMAIN
Run Code Online (Sandbox Code Playgroud)

扩展为:

"secure"domain.org
Run Code Online (Sandbox Code Playgroud)

您可能想尝试使用'#`''stringizing'运算符:

#define IV_SECURE "secure." #IV_DOMAIN
Run Code Online (Sandbox Code Playgroud)

但这不起作用,因为它只适用于宏参数 - 而不仅仅是任何旧的宏.

当你使用令牌粘贴('##')或字符串化('#')预处理操作符时,要注意的一件事是你必须使用额外的间接级别才能在所有情况下正常工作.

如果你不这样做,并且传递给令牌粘贴操作符的项目本身就是宏,你将获得可能不是你想要的结果:

#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__)));
}
Run Code Online (Sandbox Code Playgroud)

输出:

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

desired result:
function_name21
Run Code Online (Sandbox Code Playgroud)

因此,使用上面的原始IV_DOMAIN定义和实用程序宏,您可以这样做以获得您想要的:

// Sub-Domain
#define IV_SECURE "secure." STRINGIFY( IV_DOMAIN)   //secure.domain.org etc
#define IV_MOBILE "m." STRINGIFY( IV_DOMAIN)
Run Code Online (Sandbox Code Playgroud)


rpe*_*ich 8

接下来的字符串由C编译器组合在一起.

#define DOMAIN "example.com"
#define SUBDOMAIN "test." DOMAIN
const char *asCString = SUBDOMAIN;
NSString *asNSString = @SUBDOMAIN;
Run Code Online (Sandbox Code Playgroud)


rme*_*dor 7

我看到你的第一个问题有很多正确的答案,但是你的第二个问题没有,所以这就是:我认为这是一个糟糕的主意.为什么要重建软件(特别是发布版本)只是为了更改服务器名称?另外,您如何知道哪个版本的软件指向哪个服务器?您必须构建一个在运行时检查的机制.如果它在您的平台上完全可行,我建议您从配置文件加载域/ URL.只有最小的嵌入式平台可能不是"实用"的目的:)


Jar*_*Par 6

尝试使用##运算符

#define IV_SECURE secure.##IV_DOMAIN
Run Code Online (Sandbox Code Playgroud)


Dav*_*ley 5

您需要的是#和##运算符以及自动字符串连接.

#preprocessing操作符将宏参数转换为字符串.##运算符将两个标记(例如宏参数)粘贴在一起.

我想到的可能性是

#define IV_DOMAIN domain.org
#define IV_SECURE(DOMAIN) "secure." #DOMAIN
Run Code Online (Sandbox Code Playgroud)

这应该改变IV_SECURE

#define IV_SECURE "secure." "domain.org"
Run Code Online (Sandbox Code Playgroud)

它将自动连接到"secure.domain.org"(假设C中的翻译阶段与C++相同).

另一个编辑:请,请阅读评论,这些评论显示我是如何感到困惑的.请记住,我在C中经验丰富,虽然可能是生锈的.我会删除这个答案,但我想我会留下它作为一个例子,让C预处理器感到困惑是多么容易.