字符串化 - 它是如何工作的?

Mar*_* A. 50 c c++ stringification c-preprocessor

我知道:

#define foo 4  
#define str(s) #s
Run Code Online (Sandbox Code Playgroud)

str(foo)写出:"foo"因为字符串化的第一个文本扩展的执行,但这样的:

 #define xstr(s) str(s)
 #define str(s) #s
 #define foo 4
Run Code Online (Sandbox Code Playgroud)

xstr(foo)写出:"4".

为什么?该过程涉及哪些步骤?

Eri*_*hil 55

宏扩展的相关步骤是:(的每个C 2011 [n1570] 6.10.3.1和C++ 1998 16.3.1):

  1. 处理前缀为#或的处理令牌##.
  2. 将宏替换应用于每个参数.
  3. 将每个参数替换为上述宏替换的相应结果.
  4. 重新扫描更多宏.

因此,xstr(foo)我们有:

  1. 替换文本,str(s)包含no ###,因此没有任何反应.
  2. 参数foo被替换为4,所以就好像xstr(4)已经被使用了一样.
  3. 在替换文本中str(s),参数s替换为4,生成str(4).
  4. str(4)重新扫描.(由此产生的步骤产生”4”.)

请注意,问题str(foo)在于步骤2将替换foo4步骤1,它将参数更改为字符串.在步骤1中,foo仍然是foo; 它没有被替换4,所以结果是”foo”.

这就是使用辅助宏的原因.它允许我们执行第2步,然后使用另一个宏执行第1步.

  • 最后!在读完这个答案之后,我终于明白为什么这样做了.我甚至通过直觉正确地使用它,但是不能达到规则.`stringify`宏出现在许多地方(例如将`__LINE__`附加到标识符 - 强制它扩展而不是保留为`__LINE__`,在这种情况下你将使用`##`而不是`#`) ,或者 - 最近需要将参数传递给GCC的`_Pragma()`宏(内部?),它接受一个带引号的字符串,所以你可能需要:`#define my_pragma(arg)_Pragma(stringify("blah"#arg" blah2" ))`. (2认同)

Lol*_*4t0 13

第一个案例

  1. 评价str(foo):替换str(foo)#foo,即"foo"

第二种情况

  1. 评价xstr(foo):替换xstr(foo)str(<foo-value>),即str(4)
  2. 评价str(4):替换str(4)#4,即"4"

通常,

预处理器评估扩展宏变量的宏函数,直到它无需评估:

如果你定义

#define xstr(s) str(s) + 1
#define str(s) s + 1
Run Code Online (Sandbox Code Playgroud)

在以下代码中

#define foo 4

int main()
{
    std::cout << str(foo) << '\n' 
              << xstr(foo) << '\n' ;

} 
Run Code Online (Sandbox Code Playgroud)

它会评估像

第一串

  1. 替补str(foo)<foo-value> + 1,即4 + 1
  2. 没有什么可以替代的.精加工.

结果是4 + 1

第二串

  1. 替补xstr(foo)str(<foo-value>) + 1,即str(4) + 1
  2. 替补str(4)<4-value> + 1,即4 + 1
  3. 没有什么可以替代的.

结果是4 + 1 + 1