-3

I have some issue with this code i written. GCC does not like it :

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

But gcc display this error :

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

I read the gcc doc about variadic macro and i am not doing it wrong.

Can someone point my mistake ? I am completly lost.

edit :

I use it that way

_DEBUG_ADD("Bbox found @ %f %f %f %f", box[0], box[1], box[2], box[3]);
  • Show how you *use* that macro – Basile Starynkevitch Sep 17 '17 at 19:26
  • Don't use a macro where a function will do as well! If you had formatted that mess properly, the problem would be obvious. – too honest for this site Sep 17 '17 at 19:27
  • @BasileStarynkevitch I use it that way : _DEBUG_ADD("Bbox found @ %f %f %f %f", box[0], box[1], box[2], box[3]); – Michael Vouriz Sep 17 '17 at 19:30
  • 1
    That should go into your question (don't comment your question but edit it) – Basile Starynkevitch Sep 17 '17 at 19:30
  • @Olaf I agree, but i want to try using a macro. – Michael Vouriz Sep 17 '17 at 19:31
  • Are you sure that the backslashes are the last characters (i.e. no spaces after them) of their lines? – Basile Starynkevitch Sep 17 '17 at 19:36
  • 3
    I don't think the example of usage you showed is the one that causes the problem, but instead it's a case where there is a format strings with no arguments after it. in such case `__VA_ARGS__` will be compiled to nothing and you will a have a comma followed by closing parentheses – MByD Sep 17 '17 at 19:37
  • 2
    [Not reproducible](https://ideone.com/0TAoYK), post [mcve]. Note `_DEBUG_ADD` is **reserved**, using this identifier is UB. – n. m. could be an AI Sep 17 '17 at 19:37
  • https://stackoverflow.com/a/16502124/841108 could inspire you – Basile Starynkevitch Sep 17 '17 at 19:39
  • 1
    You can fix that by adding two # before `__VA_ARGS__`, and then the preceding comma will be removed, e.g. `sprintf(buffer, size, string, ##__VA_ARGS__)`. I'm not posting this as an answer, as I don't know that it's the actual problem.. – MByD Sep 17 '17 at 19:40
  • @BasileStarynkevitch Sure, there is no spaces – Michael Vouriz Sep 17 '17 at 19:44
  • @MByD it does not work.I normally do not need to use tokens – Michael Vouriz Sep 17 '17 at 19:46
  • Assume your source is `foo.c`; get the raw preprocessed form using something like `gcc -C -E foo.c|grep -v '^#' > foo.i` then compile with `gcc -Wall -Wextra -c foo.i` and study carefully the error messages and *locations* (they'll point into `foo.i` and you'll understand what is wrong) – Basile Starynkevitch Sep 17 '17 at 19:46
  • 2
    Note that names starting with an underscore and either another underscore or a capital letter are reserved to the implementation for any use. Do not create your own names that start with an underscore (simplistic rule, but safe), or read the details from §7.1.3 Reserved identifiers in the C standard (and similar sections in other standards, such as POSIX) and follow them. Don't use `_DEBUG_…` as a name you invent if you value your sanity. – Jonathan Leffler Sep 17 '17 at 19:49
  • @MichaelVouriz: So you prefer trying to jump from a roof just to see if it hurts? There are some things which are just a bad idea and don't gain any knowledge. – too honest for this site Sep 17 '17 at 21:57

1 Answers1

4

If I take the code fragments you showed and fill in missing bits to get a complete, compilable source file, I do not get any errors:

#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
$

This is why we make such a fuss about minimal, complete, verifiable examples. We don't want to waste a lot of time barking up the wrong tree.

However, in this case, I have a strong suspicion that your problem was actually triggered by code like 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");
}

which produces nearly the same error message you showed:

$ 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");
   ^~~~~~~~~~

When you give _DEBUG_ADD no arguments after the format string, __VA_ARGS__ expands to nothing, so the "compiler proper" sees

snprintf(buffer, size, string, );

which is indeed a syntax error. This is what the GNU comma-deletion extension is for: if you put ## between , and __VA_ARGS__, the comma will be removed when __VA_ARGS__ expands to nothing.

#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
$

Unfortunately, this extension is only available in GCC and Clang. I understand the C and C++ committees are talking about adding a comparable, but incompatible, feature Real Soon Now (see the comments on this question and its answers, and also C committee documents N2023 and N2153), but even if they do, it'll probably be a decade or so before that's ubiquitous enough to use.

Incidentally, the name _DEBUG_ADD begins with an underscore. All names beginning with underscores are reserved for internal use by the C compiler and library in at least some contexts. Until you have a lot more experience in the language, you should not give anything in your code a name beginning with an underscore. (It is OK to use things with names that begin with underscores, like __VA_ARGS__ and _IONBF, but only if they are documented.)

zwol
  • 135,547
  • 38
  • 252
  • 361