C 宏定义

C 宏定义,c,macros,C,Macros,我试图定义一个宏,其功能如下。调用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

我试图定义一个宏,其功能如下。调用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 */

在第二个宏展开中会得到一个额外的逗号,因为在宏定义中,
fmt
之后有一个无条件逗号

从宏定义中删除
fmt
参数似乎可以解决问题;格式字符串随后成为
\uu VA\u ARGS\uu
的一部分:

#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");
#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");
}
这扩展到:

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

(rdfDBG(kERROR, " " "Fail to open file %s\n", pinfile));
(rdfDBG(kERROR, " " "Insufficient Memory\n"));
顺便说一句,
似乎要求格式为字符串文字(我修改的版本保留了这一点)。你确定要这么做吗?尽管这种情况很少见,但使用非文字格式字符串还是很有用的。

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

不正确(GCC扩展中不允许的引用
\uu VA\u ARGS\uu
):

正确(未引用
\uu VA\u ARGS\uu
):

可以看出我没有使用GCC扩展,因为我使用的一些编译器不是GCC

Adam在其评论中还提到了第二种(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扩展,如果你把
##
前置到
uu VA_uargs_uu
并且零个参数匹配省略号,那么它会删除后面的逗号吗?例如,
#定义RDF_日志(fmt,…)foo(fmt,###VA_参数)
结果为
RDF_日志(“foo”)
=>
foo(“foo”)
#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");