宏在C中的深度

问题描述 投票:0回答:2

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 string macros
2个回答
1
投票

回答最初的问题:不,C 标准没有指定宏深度的限制,宏深度理解为扩展给定宏所需的递归宏扩展的最大数量。

但是,标准(C17,5.2.4.1)确实指定了有关宏的一些其他有趣的限制,包括以下内容:

  • 一次预处理同时定义4095个宏标识符 翻译单位
  • 一个宏定义中有 127 个参数
  • 一次宏调用中有 127 个参数

这些是最低限制,实施很可能提供更高的限制或根本没有固定限制(标准中的脚注鼓励这样做)。但是,在编写可移植代码时,应该牢记这一点。可能很难确保保持对宏标识符数量的限制,因为包含标准标头可能会定义许多不受应用程序代码控制的宏。


0
投票

让我们一次构建一个:

#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);

没有进一步定义的宏可以扩展,所以这就是最终结果。

© www.soinside.com 2019 - 2024. All rights reserved.