C 中宏的深度有限制吗?
我编写了一个宏,通过调用
string##n
宏来字符串化 n 个宏参数。但是,当我尝试在另一个宏中使用它时,它似乎无法评估属性。
例如
#include <stdint.h>
#define NARGS(ARGS...) NARGS_HELPER1(ARGS, 9, 8, 7, 6, 5, 4, 3, 2, 1)
#define NARGS_HELPER1(ARGS...) NARGS_HELPER2(ARGS)
#define NARGS_HELPER2(X1, X2, X3, X4, X5, X6, X7, X8, X9, N, ...) N
#define STRINGIFY(N, ARGS...) STRING##N(ARGS)
#define STRING1(X1) {#X1}
#define STRING2(X1, X2) {#X1, #X2}
#define STRING3(X1, X2, X3) {#X1, #X2, #X3}
#define STRING4(X1, X2, X3, X4) {#X1, #X2, #X3, #X4}
#define STRING5(X1, X2, X3, X4, X5) {#X1, #X2, #X3, #X4, #X5}
#define STRING6(X1, X2, X3, X4, X5, X6) {#X1, #X2, #X3, #X4, #X5, #X6}
#define STRING7(X1, X2, X3, X4, X5, X6, X7) {#X1, #X2, #X3, #X4, #X5, #X6, #X7}
#define STRING8(X1, X2, X3, X4, X5, X6, X7, X8) {#X1, #X2, #X3, #X4, #X5, #X6, #X7, #X8}
#define STRING9(X1, X2, X3, X4, X5, X6, X7, X8, X9) {#X1, #X2, #X3, #X4, #X5, #X6, #X7, #X8, #X9}
#define CLOSURE(NAME, ARGS...) \
const uint8_t NAME##_args_n = NARGS(ARGS); \
const char NAME##_args_types[][NAME##_args_n] = STRINGIFY(NARGS(ARGS), ARGS)
CLOSURE(func, int, float, char);
调用
CLOSURE
宏后,我在 STRINGIFY
评估中得到一些垃圾值:
const uint8_t func_args_n = 3;
const char func_args_types[][func_args_n] = STRINGNARGS(int, float, char)(int, float, char);
我还感兴趣的是为什么
ARGS
周围的括号消失了,以及为什么参数似乎是重复的?
回答最初的问题:不,C 标准没有指定宏深度的限制,宏深度理解为扩展给定宏所需的递归宏扩展的最大数量。
但是,标准(C17,5.2.4.1)确实指定了有关宏的一些其他有趣的限制,包括以下内容:
这些是最低限制,实施很可能提供更高的限制或根本没有固定限制(标准中的脚注鼓励这样做)。但是,在编写可移植代码时,应该牢记这一点。可能很难确保保持对宏标识符数量的限制,因为包含标准标头可能会定义许多不受应用程序代码控制的宏。
让我们一次构建一个:
#define CLOSURE(NAME, ARGS...) STRINGIFY(NARGS(ARGS), ARGS)
CLOSURE(func, int, float, char);
这扩展到:
STRINGIFY(NARGS(int, float, char), int, float, char);
接下来,
STRINGIFY()
被扩展,所以添加该定义:
#define CLOSURE(NAME, ARGS...) STRINGIFY(NARGS(ARGS), ARGS)
#define STRINGIFY(N, ARGS...) STRING##N(ARGS)
CLOSURE(func, int, float, char);
在这个展开式中,
N
是NARGS(int, float, char)
,ARGS
是int, float, char
,所以我们得到:
STRINGNARGS(int, float, char)(int, float, char);
没有进一步定义的宏可以扩展,所以这就是最终结果。