C预处理器字符串怪异

Bla*_*iev 5 c stringification c-preprocessor

我正在定义一个宏,它计算为一个常量字符串,保存文件名和行号,用于记录目的.

它工作正常,但我无法弄清楚为什么需要2个额外的宏 - STRINGIFY而且TOSTRING,当直觉暗示时__FILE__ ":" #__LINE__.

#include <stdio.h>

#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define THIS_ORIGIN (__FILE__ ":" TOSTRING(__LINE__))

int main (void) {
  /* correctly prints "test.c:9" */
  printf("%s", THIS_ORIGIN);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

这对我来说似乎是一个丑陋的黑客.

具体是什么,这样逐步发生阶段有人能解释__LINE__正确字符串化,为什么既不__FILE__ ":" STRINGIFY(__LINE__)__FILE__ ":" #__LINE__作品?

Jan*_*dec 7

因为扩张的顺序.在海湾合作委员会的文件说:

宏参数在被替换为宏体之前完全是宏扩展的,除非它们被字符串化或粘贴到其他标记.替换后,将再次扫描整个宏体(包括替换参数),以便扩展宏.结果是参数被扫描两次以扩展其中的宏调用.

因此,如果参数将被字符串化,则不会首先展开它.您将在括号中获取文字文本.但如果它被传递给另一个宏,它就会被扩展.因此,如果要扩展它,则需要两个级别的宏.

这样做是因为在某些情况下您希望在字符串化之前扩展参数,最常见的是assert()宏.如果你写:

assert(MIN(width, height) >= 240);
Run Code Online (Sandbox Code Playgroud)

你想要的消息是:

Assertion MIN(width, height) >= 240 failed
Run Code Online (Sandbox Code Playgroud)

而不是MIN宏扩展到的一些疯狂的东西(在gcc中它使用了几个特定于gcc的扩展,并且是非常长的IIRC).