停止宏扩展

Stopping macro expansion

我对宏扩展延迟有疑问。这是一个例子:

#include <stdio.h>

#define CONST_ABC 15
#define CONST_5 7
#define ABC 5

#define PRINT(x) printf("CONST=%d\n", CONST_ ## x)

// The problematic macro
#define PRINT2(x) PRINT(x)

int main(int argc, char *argv[])
{
    PRINT(ABC); // Prints 15 - OK
    PRINT2(ABC); // Prints 7 - Not OK.
}

如何定义 PRINT2 宏以便它使用 PRINT 并且结果为 15?我得到:

CONST=15
CONST=7

并且想得到:

CONST=15
CONST=15

它要求你至少有一个 C99 编译器,因为 C99 允许空宏参数。然而,一些编译器可能允许它们作为扩展,即使在 C89 模式下也是如此。这是代码:

#include <stdio.h>

#define CONST_ABC 15
#define CONST_5 7
#define ABC 5

#define PRINT(x) printf("CONST=%d\n", CONST_ ## x)

// The problematic macro
#define PRINT2(x, y) PRINT(x ## y)

int main(int argc, char *argv[])
{
    PRINT(ABC); // Prints 15 - OK
    PRINT2(ABC,); // Prints 7 - Not OK.
}

第二个参数(即y)为空,使其成为空预处理标记## 运算符可防止参数扩展,因此串联的结果与 x 参数相同。

C11 6.10.3.1/p1 参数替换(强调我的):

After the arguments for the invocation of a function-like macro have been identified, argument substitution takes place. A parameter in the replacement list, unless preceded by a # or ## preprocessing token or followed by a ## preprocessing token (see below), is replaced by the corresponding argument after all macros contained therein have been expanded. Before being substituted, each argument’s preprocessing tokens are completely macro replaced as if they formed the rest of the preprocessing file; no other preprocessing tokens are available.

宏替换基本上是这样进行的:

  1. 找到一个标记,它是一个宏名
  2. 宏的参数收集
  3. 实参替换宏定义体中的形参
  4. 因此替换的参数是完全宏替换的,不包括输入的其余部分;也可以在此阶段执行字符串化;
  5. 执行令牌粘贴运算符
  6. 因此被替换的序列与输入的其余部分一起被重新扫描以进行进一步的宏替换

(加上一些定义不明确的规则,当宏被禁止替换时)

防止宏参数在 4 中被宏替换的唯一方法。 用于在其后面或前面加上标记粘贴运算符 (##)。

但是,在 5. 中,粘贴运算符必须执行操作 正在讨论的论点和一个特殊的地标标记。仅为空参数替换插入地标标记。

检查这个,它可能会让你对你的真实代码有所了解:

#define PRINT2(noreplace,x) PRINT(noreplace ## x)

PS。是的,"noreplace" 是空的 :)

PRINT2(,ABC)