2011-02-24 63 views
15

是否可以在预处理过程中连接字符串?使用预处理器的字符串串联

我发现这个例子

​​

但是它并没有为我工作 - 打印出“你好”当我用gcc -std=c99

UPD这个例子貌似现在的工作。但是,它是c预处理器的一个正常特性吗?

回答

36

级联相邻串litterals的不预处理器的功能,它的核心是语言(C和C++)的功能。你可以这样写:

printf("Hello " 
     " world\n"); 
10

gcc online docs

的 '##' 的预处理操作者进行标记粘贴。当一个宏展开时,每个'##'运算符两边的两个令牌被合并成一个单独的令牌,然后替换宏扩展中的'##'和两个原始令牌。

考虑一个解释命名命令的C程序。有可能需要在命令表,或许声明为结构数组如下:

struct command 
{ 
    char *name; 
    void (*function) (void); 
}; 

struct command commands[] = 
{ 
    { "quit", quit_command }, 
    { "help", help_command }, 
    ... 
}; 

这将是清洁不必须给每个命令的名字两次,一次在字符串常量,一次在功能名称。以命令的名称作为参数的宏可以使这不必要。可以使用字符串化创建字符串常量,并通过将参数与_command连接来创建函数名称。下面是它是如何做:

#define COMMAND(NAME) { #NAME, NAME ## _command } 

struct command commands[] = 
{ 
    COMMAND (quit), 
    COMMAND (help), 
    ... 
}; 
17

你确实可以连接预处理器中的标记,但要小心,因为它很棘手。关键是##运算符。如果你在你的代码的顶部抛出这样的:

#define myexample(x,y,z) int example_##x##_##y##_##z## = x##y##z 

话,基本上,这是什么呢,是在预处理过程中,它会采取任何调用该宏,如下列:

myexample(1,2,3); 

,它会从字面上变成

int example_1_2_3 = 123; 

这可以让你一吨的灵活性,同时编码,如果你正确地使用它,但它并不完全适用你如何尝试使用它。用一点按摩,你可以让它工作。为你的榜样

一个可能的解决方案可能是:

#define H "Hello " 
#define W "World!" 
#define concat_and_print(a, b) cout << a << b << endl 

,然后像做

concat_and_print(H,W); 
+0

这是一个C++标准或只是一个gcc功能? – bibi 2016-12-09 07:38:39

+0

在你的例子中,连接是在运行时完成的,而不是由预处理器完成。 – 2017-06-13 15:19:13

4

我只是想我要补充一点,引用源,为什么这个问题的解答。

C99标准§5.1.1.2定义了C代码的转换阶段。第6条规定:

  • 相邻字符串文字令牌是级联。
  • 类似地,在C++标准(ISO 14882)§2.1定义翻译的相位。这里子部分6陈述:

    6将相邻的普通字符串文字标记连接在一起。相邻的宽字符串文字标记是连接的。

    这就是为什么你可以将它们彼此相邻的简单连接字符串:

    printf("string"" one\n"); 
    
    >> ./a.out 
    >> string one 
    

    问题的预处理部分的#define预处理指令,它不会取代简单地使用从标识符(H)到字符串("Hello ")。