C variadic宏不编译

时间:2017-09-17 19:25:13

标签: c gcc macros variadic-macros

我写的这段代码有些问题。海湾合作委员会不喜欢它:

#define _DEBUG_ADD(string, ...)                     \
do{                                                 \
if (EVALUATE_TYPE(string)){                         \
size_t  size = strlen(string) + BUFFER_SIZE_DEBUG;  \
char    *buffer = alloca(size);                     \
bzero(buffer, size);                                \
snprintf(buffer, size, string, __VA_ARGS__);        \
fwrite(buffer, strlen(buffer), 1, DEBUG_STREAM); }} \
while(0)

但是gcc显示这个错误:

../debug.h:33:42: error: expected expression before ')' token
                    snprintf(buffer, size, string, __VA_ARGS__);

我阅读了关于variadic macro的gcc文档,我没有做错。

有人能指出我的错误吗?我完全迷失了。

编辑

我这样使用

_DEBUG_ADD("Bbox found @ %f %f %f %f", box[0], box[1], box[2], box[3]);

1 个答案:

答案 0 :(得分:2)

如果我使用您显示的代码片段并填写缺失的位以获得完整的,可编译的源文件,我不会收到任何错误:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define _DEBUG_ADD(string, ...)                     \
do{                                                 \
if (EVALUATE_TYPE(string)){                         \
size_t  size = strlen(string) + BUFFER_SIZE_DEBUG;  \
char    *buffer = alloca(size);                     \
bzero(buffer, size);                                \
snprintf(buffer, size, string, __VA_ARGS__);        \
fwrite(buffer, strlen(buffer), 1, DEBUG_STREAM); }} \
while(0)

#define EVALUATE_TYPE(s) 1
#define BUFFER_SIZE_DEBUG 128
#define DEBUG_STREAM stderr

void test(double box[4])
{
  _DEBUG_ADD("Bbox found @ %f %f %f %f", box[0], box[1], box[2], box[3]);
}

- &GT;

$ gcc -fsyntax-only -Wall test.c
$

这就是我们对minimal, complete, verifiable examples这么大惊小怪的原因。我们不想浪费大量时间咆哮错误的树。

然而,在这种情况下,我强烈怀疑您的问题实际上是由 this 等代码触发的:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define _DEBUG_ADD(string, ...)                     \
do{                                                 \
if (EVALUATE_TYPE(string)){                         \
size_t  size = strlen(string) + BUFFER_SIZE_DEBUG;  \
char    *buffer = alloca(size);                     \
bzero(buffer, size);                                \
snprintf(buffer, size, string, __VA_ARGS__);        \
fwrite(buffer, strlen(buffer), 1, DEBUG_STREAM); }} \
while(0)

#define EVALUATE_TYPE(s) 1
#define BUFFER_SIZE_DEBUG 128
#define DEBUG_STREAM stderr

void test(void)
{
  _DEBUG_ADD("got here 1");
}

会产生几乎相同的错误消息:

$ gcc -fsyntax-only -Wall test.c
test.c: In function ‘test’:
test.c:11:43: error: expected expression before ‘)’ token
 snprintf(buffer, size, string, __VA_ARGS__);        \
                                           ^
test.c:21:3: note: in expansion of macro ‘_DEBUG_ADD’
   _DEBUG_ADD("got here 1");
   ^~~~~~~~~~

当你在格式字符串之后给_DEBUG_ADD没有参数时,__VA_ARGS__会扩展为空,所以&#34;编译器正确&#34;认为

snprintf(buffer, size, string, );

这确实是语法错误。这就是GNU comma-deletion extension的用途:如果您将##放在,__VA_ARGS__之间,则当__VA_ARGS__扩展为空时,将删除逗号。< / p>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define _DEBUG_ADD(string, ...)                     \
do{                                                 \
if (EVALUATE_TYPE(string)){                         \
size_t  size = strlen(string) + BUFFER_SIZE_DEBUG;  \
char    *buffer = alloca(size);                     \
bzero(buffer, size);                                \
snprintf(buffer, size, string, ##__VA_ARGS__);      \
fwrite(buffer, strlen(buffer), 1, DEBUG_STREAM); }} \
while(0)

#define EVALUATE_TYPE(s) 1
#define BUFFER_SIZE_DEBUG 128
#define DEBUG_STREAM stderr

void test(void)
{
  _DEBUG_ADD("got here 1");
}

- &GT;

$ gcc -fsyntax-only -Wall test.c
$

不幸的是,此扩展仅适用于GCC和Clang。我理解C和C ++委员会正在讨论添加类似但不兼容的功能Real Soon Now(请参阅this question及其答案的评论,以及C委员会文档N2023和{{3} }),但即使他们这样做,也可能在此之前大约十年左右,无处不在。

顺便提一下,名称_DEBUG_ADD以下划线开头。所有以下划线开头的名称至少在某些上下文中保留供C编译器和库内部使用。在您拥有很多语言经验之前,您不应该在代码中提供以下划线开头的名称。 (可以使用名称以下划线开头的内容,例如__VA_ARGS___IONBF,但前提是它们都有记录。)