"#define STR(a) #a" 是什么意思?

17

我正在阅读phoneME的源代码。这是一个开源的JavaME实现。它是用C++编写的,我偶然发现了这个:

// Makes a string of the argument (which is not macro-expanded)
#define STR(a) #a

我懂C和C++,但我从未见过像这样的东西。在#a中的#是什么意思?

同时,在同一个文件中,还有:

// Makes a string of the macro expansion of a
#define XSTR(a) STR(a)

我的意思是,如果定义一个新的宏只是调用一个已有的宏,那么这样做有什么用呢?

源代码在https://phoneme.dev.java.net/source/browse/phoneme/releases/phoneme_feature-mr2-rel-b23/cldc/src/vm/share/utilities/GlobalDefinitions.hpp?rev=5525&view=markup。您可以使用CTRL+F查找。


显然,这种(特别是STRXSTR宏的组合)被称为“双字符串技巧”。在问题如何确切地使用双字符串技巧?中有一个非常好的解释。 - sleske
4个回答

21

在第一个定义中,#a 的意思是将宏参数打印为字符串。例如,这将把 STR(foo) 转换为 "foo",但它不会对其参数进行宏展开。

第二个定义与第一个定义没有什么不同,但是通过将其参数传递给另一个宏,它强制执行其参数的完全宏展开。因此,XSTR(expr) 创建了一个包含所有宏完全展开的 expr 的字符串。


5

#是字符串化操作符。预处理器将参数转换为一个字符串。

比如你有:

STR(MyClass);

它将被预处理为:

"MyClass";

使用XSTR()的间接级别与宏扩展规则有关。

4
#a 被称为 字符串化操作符。它将形式参数(在本例中为 a)放入双引号中并将其转换为字符串。

因此,如果您有以下内容:

string s = STR("my quoted string");
cout << s;

输出结果将是:
"my quoted string"

5
不是很重要,但我认为“stringizer”是微软专有名词。通常使用的是“stringify”操作符,这个过程称为“字符串化”。 - Michael Mrozek
2
如果你要编造单词,那么"stringify"和"stringise"一样可信。我建议使用"stringulate"。 - Mike Seymour
1
@John,我相信你的意思是:string s = STR(my quoted string);,也就是说,不要加引号(并且要加分号)。 - Alok Singhal
@John Dibling,@Michael Mrozek:至少在C++中,标准的那一部分标题为[cpp.stringize] - Jerry Coffin
1
@Alok:不,我指的是引号。关键是字符串化程序(或者你个人喜欢怎么称呼它我都无所谓)会返回一个带引号的字符串。但你说得对,缺少分号。已添加。 - John Dibling
@John,是的,我不知道当时在想什么。谢谢。 - Alok Singhal

4

首先,您应该知道这对宏实际上是相当常见的。第一个宏正如注释所说的那样——通过用双引号括起来将参数转换为字符串。

第二个宏用于导致参数的宏展开。您通常会像这样一起使用它们:

#define a value_a

printf("%s", XSTR(a));

宏扩展将把a扩展为string_a,然后字符串化会将其转换为字符串,因此输出将是value_a

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接