Если я возьму фрагменты кода, которые вы показали, и заполню недостающие биты, чтобы получить полный компилируемый исходный файл, я не получу никаких ошибок:
#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]);
}
-->
$ gcc -fsyntax-only -Wall test.c
$
Вот почему мы поднимаем такой шум вокруг минимальных, полных, поддающихся проверке примеров. Мы не хотим тратить много времени на то, чтобы лаять не на то дерево.
Однако в данном случае у меня есть сильное подозрение, что ваша проблема на самом деле была вызвана таким кодом, как этот:
#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__
расширяется до нуля, поэтому «собственный компилятор» видит
snprintf(buffer, size, string, );
что действительно является синтаксической ошибкой. Это то, что GNU расширение для удаления запятых для: если вы поместите ##
между ,
и __VA_ARGS__
, запятая будет удалена, когда __VA_ARGS__
превратится в ничто.
#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
$
К сожалению, это расширение доступно только в GCC и Clang. Я понимаю, что комитеты C и C++ говорят о добавлении сопоставимой, но несовместимой функции Real Soon Now (см. комментарии на этот вопрос и ответы на него, а также документы комитета C N2023 и N2153), но даже если они это сделают, вероятно, пройдет десятилетие или около того, прежде чем это станет достаточно повсеместным для использования.
Кстати, имя _DEBUG_ADD
начинается с подчеркивания. Все имена, начинающиеся с подчеркивания, зарезервированы для внутреннего использования компилятором C и библиотекой, по крайней мере, в некоторых контекстах. Пока у вас гораздо больше опыта работы с языком, вы не должны давать в своем коде имена, начинающиеся с подчеркивания. (Можно использовать элементы с именами, начинающимися с подчеркивания, например __VA_ARGS__
и _IONBF
, но только если они задокументированы.)
person
zwol
schedule
17.09.2017
__VA_ARGS__
будет скомпилировано в ничто, и у вас будет запятая, за которой следуют закрывающие скобки - person MByD   schedule 17.09.2017_DEBUG_ADD
зарезервировано, использование этого идентификатора — UB. - person n. 1.8e9-where's-my-share m.   schedule 17.09.2017__VA_ARGS__
, и тогда предыдущая запятая будет удалена, например.sprintf(buffer, size, string, ##__VA_ARGS__)
. Я не публикую это как ответ, так как не знаю, что это настоящая проблема. - person MByD   schedule 17.09.2017foo.c
; получить необработанную предварительно обработанную форму, используя что-то вродеgcc -C -E foo.c|grep -v '^#' > foo.i
, затем скомпилировать с помощьюgcc -Wall -Wextra -c foo.i
и внимательно изучить сообщения об ошибках и местоположения (они будут указывать наfoo.i
, и вы поймете, что не так) - person Basile Starynkevitch   schedule 17.09.2017_DEBUG_…
в качестве придуманного имени, если вам дорого ваше здравомыслие. - person Jonathan Leffler   schedule 17.09.2017