宏定义

时间:2011-10-17 02:31:35

标签: c macros

我尝试定义一个如下功能的宏。调用1没有问题,但调用2提示编译器错误,因为第3个参数不可用。如何定义一个支持call 1和call 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 个答案:

答案 0 :(得分: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"));

顺便说一句," "似乎要求格式为字符串文字(我的修改版本保留了这个)。你确定要这么做吗?尽管很少见,但是使用非文字格式字符串会非常有用。

答案 1 :(得分: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需要一个逗号和至少一个参数。