C++ 使用预处理器进行字符串连接

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5106280/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 17:25:00  来源:igfitidea点击:

String concatenation using preprocessor

c++cstring

提问by Vladimir Keleshev

is it possible to concatenate strings during preprocessing?

是否可以在预处理期间连接字符串?

I found this example

我找到了这个例子

#define H "Hello "
#define W "World!"
#define HW H W

printf(HW); // Prints "Hello World!"

However it does not work for me - prints out "Hello" when I use gcc -std=c99

但是它对我不起作用 - 当我使用时打印出“Hello” gcc -std=c99

UPDThis example looks like working now. However, is it a normal feature of c preprocessor?

UPD这个例子现在看起来可以工作了。但是,这是c预处理器的正常功能吗?

回答by AProgrammer

Concatenation of adjacent string litterals isn't a feature of the preprocessor, it is a feature of the core languages (both C and C++). You could write:

相邻字符串字面量的连接不是预处理器的特性,而是核心语言(C 和 C++)的特性。你可以写:

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

回答by NDL

You can indeed concatenate tokens in the preprocessor, but be careful because it's tricky. The key is the ## operator. If you were to throw this at the top of your code:

您确实可以在预处理器中连接令牌,但要小心,因为它很棘手。关键是## 运算符。如果你把它放在代码的顶部:

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

then basically, what this does, is that during preprocessing, it will take any call to that macro, such as the following:

那么基本上,这样做的作用是,在预处理期间,它将接受对该宏的任何调用,例如:

myexample(1,2,3);

and it will literally turn into

它会从字面上变成

int example_1_2_3 = 123;

This allows you a ton of flexibility while coding if you use it correctly, but it doesn't exactly apply how you are trying to use it. With a little massaging, you could get it to work though.

如果您正确使用它,这可以让您在编码时具有很大的灵活性,但它并不完全适用于您尝试使用它的方式。稍微按摩一下,你就可以让它发挥作用。

One possible solution for your example might be:

您的示例的一种可能的解决方案可能是:

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

and then do something like

然后做类似的事情

concat_and_print(H,W);

回答by NDL

From gcc online docs:

来自gcc 在线文档

The '##' preprocessing operator performs token pasting. When a macro is expanded, the two tokens on either side of each '##' operator are combined into a single token, which then replaces the '##' and the two original tokens in the macro expansion.

Consider a C program that interprets named commands. There probably needs to be a table of commands, perhaps an array of structures declared as follows:

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

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

It would be cleaner not to have to give each command name twice, once in the string constant and once in the function name. A macro which takes the name of a command as an argument can make this unnecessary. The string constant can be created with stringification, and the function name by concatenating the argument with _command. Here is how it is done:

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

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

'##' 预处理运算符执行标记粘贴。扩展宏时,每个“##”运算符两侧的两个标记合并为一个标记,然后替换宏扩展中的“##”和两个原始标记。

考虑一个解释命名命令的 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),
   ...
 };

回答by Mike

I just thought I would add an answer that cites the source as to why this works.

我只是想我会添加一个答案,引用来源说明为什么会这样。

The C99 standard §5.1.1.2 defines translation phases for C code. Subsection 6 states:

C99 标准 §5.1.1.2 定义了 C 代码的翻译阶段。第 6 款规定:

  1. Adjacent string literal tokens are concatenated.
  1. 连接相邻的字符串文字标记。

Similarly, in the C++ standards (ISO 14882) §2.1 defines the Phases of translation. Here Subsection 6 states:

同样,在 C++ 标准 (ISO 14882) §2.1 中定义了翻译阶段。此处第 6 款规定:

6 Adjacent ordinary string literal tokens are concatenated. Adjacent wide string literal tokens are concatenated.

6 相邻的普通字符串文字标记被连接起来。连接相邻的宽字符串文字标记。

This is why you can concatenate strings simply by placing them adjacent to one another:

这就是为什么您可以通过将字符串彼此相邻来连接字符串的原因:

printf("string"" one\n");

>> ./a.out
>> string one

The preprocessing part of the question is simply the usage of the #definepreprocessing directive which does the substitution from identifier (H) to string ("Hello ").

问题的预处理部分只是#define预处理指令的使用,该指令将标识符 ( H)替换为字符串 ( "Hello ")。