开发者

macro definition

I tried to define a macro functioned as below. Call 1 has no problem, but Call 2 prompted compiler error because 3rd argument is not available. How to define a macro which support both call 1 and 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"); /*开发者_如何学Python call 2 , compiler -> error: expected expression before ')' token */


You're getting an extra comma in the second macro expansion, because you have an unconditional comma after fmt in the macro definition.

Dropping the fmt parameter from the macro definition seems to fix the problem; the format string then becomes part of __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");

This expands to:

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

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

Incidentally, it looks like the " " is intended to require the format to be a string literal (and my modified version preserves this). Are you sure you want to do that? Though it's rare, it can be useful to have a non-literal format string.


GCC Extensions

GCC has an extension to handle that (note the missing comma before the ...):

Incorrect (references __VA_ARGS__ which is not allowed in the GCC extension):

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

Correct (not referencing __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");
}

You can tell I don't use the GCC extension - because I use some compilers that are not GCC.

There is also the second (GCC-specific) mechanism mentioned by Adam in his comment:

#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");
}

Standard C99

Failing that, you have to use the C99 standard mechanism:

#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");

This basically cheats or circumvents the problem for this context. In the general case, C99 requires a comma and at least one argument.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜