宏定义

发布于 2024-12-10 09:51:22 字数 441 浏览 0 评论 0原文

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

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"); /* call 2 , compiler -> error: expected expression before ')' token */

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

葮薆情 2024-12-17 09:51:22

您在第二个宏扩展中得到了一个额外的逗号,因为在宏定义中的 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"));

顺便说一句,看起来 " " 旨在要求格式为字符串文字(我修改过的版本保留了这一点)。您确定要这样做吗?虽然这种情况很少见,但使用非文字格式字符串可能会很有用。

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.

杀手六號 2024-12-17 09:51:22

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 的编译器。

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

Standard 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 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文