我尝试定义一个如下功能的宏。调用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 */
答案 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扩展中不允许引用__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标准机制:
#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需要一个逗号和至少一个参数。