11

I have a simple: #define log(text, ...) fprintf(stderr, "stuff before" text "stuff after", ## __VA_ARGS__); which is triggering: error: ISO C99 requires at least one argument for the "..." in a variadic macro [-Werror]

Should using -std=c11 and -Wno-variadic-macros not fix this error / warning?

Throwing #pragma GCC system_header in the header file before the define of log fixes this issue (haven't necessarily tested if the outputted binary works...) but this seems sort of hacky and I'm not entirely sure the ramifications of this.

Here's an example of expected behaviour: https://stackoverflow.com/a/31327708/5698848

From GNU

-Wvariadic-macros

    Warn if variadic macros are used in ISO C90 mode, or if the GNU alternate syntax is used in ISO C99 mode.
    This is enabled by either -Wpedantic or -Wtraditional.
    To inhibit the warning messages, use -Wno-variadic-macros.

Any idea on an elegant solution to stop this warning / error from legal GNU GCC C code? Why does it say I'm using C99 and why doesn't the flag to disable the warning for C99 work? Line looks like:

gcc -c src/file.c -Wall -Werror -Wextra -pedantic -Wfloat-equal -Wwrite-strings -Wcast-qual -Wunreachable-code -Wcast-align -Wstrict-prototypes -Wundef -Wshadow -Wstrict-aliasing -Wstrict-overflow -Wno-variadic-macros -g3 -std=c11 -O2 -flto -Iinclude/ -MMD -MF depend/file.d -o bin/file.o

Note that -pedantic is indeed the culprit.


MCVE

c.c

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

#define log(text, ...) fprintf(stderr, "stuff before" text "stuff after", ## __VA_ARGS__);

int main(void)
{

    log("should work, but doesn't");
    log("works fine: %s", "yep");

    return EXIT_SUCCESS;
}

Makefile

all:
    gcc c.c -Wall -Werror -Wextra -pedantic -Wfloat-equal -Wwrite-strings -Wcast-qual -Wunreachable-code -Wcast-align -Wstrict-prototypes -Wundef -Wshadow -Wstrict-aliasing -Wstrict-overflow -Wno-variadic-macros -g3 -std=c11 -O2

Note: Removing pedantic compiles fine - gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609

M.M
  • 138,810
  • 21
  • 208
  • 365
Ray C
  • 547
  • 2
  • 7
  • 24
  • `#define log(text, ...) fprintf(stderr, "stuff before" text "stuff after", ## __VA_ARGS__);` is a troublesome macro. If `text` isn't a string literal, it's broken, which is not what's expected from a `printf`-style call. – Andrew Henle May 16 '17 at 01:37
  • Why are you reading documentation from GCC 2.95.2? That's ancient. – aschepler May 16 '17 at 01:52
  • *That part is not necessarily important.* You're hardly the first to write a variadic logging macro. If you don't think what I said is important, you've missed the connection with your problem. And once you address that, you'll also wind up with a macro that makes a lot more sense when you look at it a few months or even years from now... – Andrew Henle May 16 '17 at 01:52
  • `##__VA_ARGS__` is a GCC extension. If you specify ISO conformance then you don't get gcc extensions (mostly). Have you tried specifying GNU conformance, e.g. `-std=gnu11` ? – M.M May 16 '17 at 01:53
  • Also, you should post a MCVE (I can't reproduce your error trying various versions of gcc) – M.M May 16 '17 at 01:56
  • What do you mean by "overriding my given standard". You supplied flag `-std=c11` and you are getting C11 behaviour. What did you expect? – M.M May 16 '17 at 02:02
  • 1
    The specification is the same in C99 and C11. Probably gcc did not bother to make the error message change in accordance to your flag. You could report a bug although I doubt anybody would care enough to spend their time adding this feature... – M.M May 16 '17 at 02:05
  • To conclude whether something is the same for both standards, you read the standards documents. – M.M May 16 '17 at 02:21
  • 1
    @jake: You should re-read what `-Wpedantic` (`-pedantic` is the same, but deprecated for obvious reasons) actually means. – too honest for this site May 16 '17 at 02:39
  • Maybe another workaround to silent the compiler is to forward variadic arguments via `va_list`, `va_start(...)` and `va_end(...)` from `stdarg.h` – IMAN4K Feb 28 '23 at 15:50

2 Answers2

13

In ISO C99 and C11, when you define a macro like:

#define log(text, ...)   something

then any invocation of the macro must take at least 2 arguments. Your code is ill-formed in ISO C (all versions).

The GCC flag -pedantic, according to the documentation, means:

Issue all the warnings demanded by strict ISO C and ISO C++; reject all programs that use forbidden extensions, and some other programs that do not follow ISO C and ISO C++. For ISO C, follows the version of the ISO C standard specified by any -std option used.

The GCC developers decided to include code using this extension under "some other programs that do not follow ISO C". If you want to use this non-standard extension in your code, then you should not use the -pedantic flag.

The GCC developers also did not bother to modify the text of the error message to say "ISO C11 forbids..." if you requested C11 conformance. If this concerns you then perhaps you could submit a patch.


Regarding -Wno-variadic-macros, the documentation is:

Warn if variadic macros are used in ISO C90 mode, or if the GNU alternate syntax is used in ISO C99 mode.

By "GNU alternate syntax", it appears that they mean the GNU syntax for enabling variadic macros in the first place prior to C99, as described in the GCC documentation (and not the extension to provide fewer arguments than the minimum):

GCC has long supported variadic macros, and used a different syntax that allowed you to give a name to the variable arguments just like any other argument. Here is an example:

#define debug(format, args...) fprintf (stderr, format, args)
M.M
  • 138,810
  • 21
  • 208
  • 365
  • I don't get the sense of this warning : `warning: ISO C++11 requires at least one argument for the "..." in a variadic macro` Isn't the ## before __VA_ARGS__ supposed to delete the comma if it isn't used ? That doesn't make any the -pedantic flag output this. – Tesla123 Mar 01 '23 at 09:54
  • @Tesla123 the "delete the comma" behaviour is a GNU extension and not part of the standard. – M.M Mar 01 '23 at 20:52
4

Here is the solution for C99:

#define debug_print(...) \
        do { fprintf(stderr, "%s:%d:%s(): ",__FILE__, __LINE__, __func__);\
             fprintf(stderr, __VA_ARGS__); } while (0)
jean-loup
  • 580
  • 4
  • 17