宏定义

3
我尝试定义了一个宏函数,如下所示。调用1没有问题,但是调用2会提示编译器错误,因为缺少第三个参数。如何定义一个宏函数可以同时支持调用1和调用2?
#define RDF_LOG(dbglevel, fmt, ...) (rdfDBG(dbglevel, " " fmt, __VA_ARGS__))
void rdfDBG(int dbglevel, const char *fmt, ...) { /* printf debug message */ }

RDF_LOG(kERROR, "Fail to open file %s\n", pinfile); /* Call 1 */
RDF_LOG(kERROR, "Insufficient Memory\n"); /* call 2 , compiler -> error: expected expression before ')' token */
2个回答

4
在第二个宏扩展中出现了多余的逗号,因为在宏定义之后,您有一个无条件的逗号跟着fmt
从宏定义中删除fmt参数似乎可以解决这个问题;然后格式字符串成为__VA_ARGS__的一部分。
#define RDF_LOG(dbglevel, ...) (rdfDBG(dbglevel, " " __VA_ARGS__))
void rdfDBG(int dbglevel, const char *fmt, ...) { /* printf debug message */ }

RDF_LOG(kERROR, "Fail to open file %s\n", pinfile); /* Call 1 */
RDF_LOG(kERROR, "Insufficient Memory\n");

这会扩展为:

void rdfDBG(int dbglevel, const char *fmt, ...) { }

(rdfDBG(kERROR, " " "Fail to open file %s\n", pinfile));
(rdfDBG(kERROR, " " "Insufficient Memory\n"));

顺便提一下,看起来 " " 的意思是要求格式为字符串文字(我的修改版本保留了这一点)。你确定要这样做吗?虽然很少,但有时使用非文本格式字符串会很有用。


2

GCC扩展

GCC有一个扩展来处理这个问题(注意在...之前缺少逗号):

不正确的写法(引用了GCC扩展中不允许使用的__VA_ARGS__):

#define RDF_LOG(dbglevel, fmt ...) (rdfDBG(dbglevel, " " fmt, __VA_ARGS__))

正确的写法(不使用__VA_ARGS__):

#define RDF_LOG(dbglevel, fmt...) (rdfDBG(dbglevel, " " fmt))
void rdfDBG(int dbglevel, const char *fmt, ...) { /* printf debug message */ }
enum { kERROR };

void x(const char *pinfile);
void x(const char *pinfile)
{
    RDF_LOG(kERROR, "Fail to open file %s\n", pinfile);
    RDF_LOG(kERROR, "Insufficient Memory\n");
}

你可以看出我不使用 GCC 扩展,因为我使用一些不是 GCC 的编译器。
亚当在他的评论中提到了第二种(仅适用于 GCC)机制。
#define RDF_LOG(dbglevel, fmt, ...) (rdfDBG(dbglevel, " " fmt, ## __VA_ARGS__))
void rdfDBG(int dbglevel, const char *fmt, ...) { /* printf debug message */ }
enum { kERROR };

void x(const char *pinfile);
void x(const char *pinfile)
{
    RDF_LOG(kERROR, "Fail to open file %s\n", pinfile);
    RDF_LOG(kERROR, "Insufficient Memory\n");
}

标准 C99

如果不行的话,你必须使用C99标准机制:

#define RDF_LOG(dbglevel, ...) (rdfDBG(dbglevel, " " __VA_ARGS__))
void rdfDBG(int dbglevel, const char *fmt, ...) { /* printf debug message */ }

RDF_LOG(kERROR, "Fail to open file %s\n", pinfile); /* Call 1 */
RDF_LOG(kERROR, "Insufficient Memory\n");

这基本上是针对这种情况的一种欺骗或规避问题的方法。在一般情况下,C99需要逗号和至少一个参数。

你的第一个例子不起作用。你确定你没有想到GCC扩展,如果在__VA_ARGS__前面加上##,并且零个参数匹配省略号,则会删除尾随逗号吗?例如:#define RDF_LOG(fmt, ...) foo(fmt, ##__VA_ARGS__) 的结果是 RDF_LOG("foo") ==> foo("foo") - Adam Rosenfield

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接