C 如何展开宏并删除逗号

C 如何展开宏并删除逗号,c,macros,c-preprocessor,variadic,variadic-macros,C,Macros,C Preprocessor,Variadic,Variadic Macros,例如,我想编写自己的printf()备选方案,但必须对变量参数执行计算: #define log(fmt_string, ...) my_log(fmt_string, pack_args(__VA_ARGS__), __VA_ARGS__) 其中pack_args(…)-也是一个宏。 我应该如何更改此代码以处理唯一的fmt_字符串存在场景 log("Some message here"); 我应该如何将此代码更改为[处理]唯一的fmt_字符串存在场景 log("Some message h

例如,我想编写自己的printf()备选方案,但必须对变量参数执行计算:

#define log(fmt_string, ...) my_log(fmt_string, pack_args(__VA_ARGS__), __VA_ARGS__)
其中pack_args(…)-也是一个宏。 我应该如何更改此代码以处理唯一的fmt_字符串存在场景

log("Some message here");
我应该如何将此代码更改为[处理]唯一的fmt_字符串存在场景

log("Some message here");
对于标准C中的可变宏,您根本无法做到这一点。该标准明确规定,在可变宏调用中,“调用中的参数应多于宏定义中的参数(不包括…)”(C2011,6.10.3/4)。您可以通过将宏更改为

#define log(...) /* ... */
。。。但是,您无法将格式字符串从其他参数中分离出来——至少不能不重新引入您现在遇到的相同问题

如果需要支持零长度变量参数列表,则需要使用真正的函数。

在中,我有两个宏

#define P00_ARG(                                               \
 _1, _2, _3, _4, _5, _6, _7, _8,                               \
 _9, _10, _11, _12, _13, _14, _15, _16,                        \
  ... etc ...                                                  \
 _153, _154, _155, _156, _157, _158, _159,                     \
 ...) _159
#define P99_HAS_COMMA(...) P00_ARG(__VA_ARGS__,                \
 1, 1, 1, 1, 1, 1, 1,                                          \
 1, 1, 1, 1, 1, 1, 1, 1,                                       \
  ... etc ....                                                 \
 1, 1, 1, 1, 1, 1, 0, 0)
您可以使用它来确定您的参数是否有逗号(因此参数的数量比您的格式多)或者没有逗号(只有一种格式)。然后,您可以使用它来构造对两个宏之一的调用:

#define log(...) log2(P99_HAS_COMMA(__VA_ARGS__), __VA_ARGS__)
#define log2(N, ...) log3(N, __VA_ARGS__)
#define log3(N, ...) log ## N(__VA_ARGS__)

#define log0(FMT)              /* your version with format only goes here */
#define log1(FMT, __VA_ARGS__) /* your version with more goes here */

gcc实际上可以删除
的前导逗号。IIRC只是以
##
(最好在文档中验证)作为扩展名作为前缀。@Olaf,作为扩展名,GCC允许使用零变量参数调用变量宏,并通过抑制逗号来处理出现在逗号和
u VA_uargs_u
之间的
#
运算符,这是正确的。也许这将有助于操作,但我很少倾向于建议合并特定于特定编译器的行为的依赖项。一般来说,我不喜欢依赖编译器特性。OTOH,我认为gcc是OSS和(其中一个)最常用的编译器,这是某种例外(如果我更了解clang/llvm,我可能会包括它们)。这是因为您不依赖于特定的供应商,但可以自己移植—如果需要的话。它也不太可能突然消失。无论如何,我认为我们应该把决定权留给OP,只是提供信息。这不就是自由的意义吗?@Olaf,我喜欢gcc,并从中获得了很多用处,但我关心的通常不是能否找到一个合适的编译器来构建我的代码。我更关心的是一个人是否可以用他想要(或需要)使用的任何编译器来构建它。@Olaf,不过,我更新了答案以限定“你根本不能这样做”的断言。与你的问题没有直接关系,但这个宏将处理两次参数。例如,
log(“foo%d”,func())将调用func两次。要解决这个问题,您可以创建一个函数,例如
my_log_pack(char const*,…)处理其参数列表两次。我不完全理解您的问题。你的例子太少了。如何定义此
pack_args
宏?如何定义我的日志功能?可能您可以锁定:。