1

What is the universal way of resolving

warning: ISO C++11 requires at least one argument for the "..." in a variadic macro

warning introduced by -pedantic flag for gcc?

Consider following example

#define FUNCTION_DECL(ret, name, ...) ret name(__VA_ARGS__)

FUNCTION_DECL(int, foo, int bar, int quax)
{
    return bar + quax;
}

FUNCTION_DECL(void, no_args)
{
}

Expansion of no_args macro produces error above.

Example of solution to that would be to have two macros and then simple overload trick

#define GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, NAME, ...) NAME
#define METHOD_DECL2(ret, name) ret name()
#define METHOD_DECL3(ret, name, ...) ret name(__VA_ARGS__)
#define METHOD_DECL(...) GET_MACRO(__VA_ARGS__, METHOD_DECL3, METHOD_DECL3, METHOD_DECL3, METHOD_DECL3, METHOD_DECL3, METHOD_DECL3, METHOD_DECL3, METHOD_DECL2)(__VA_ARGS__)

Then METHOD_DECL(void, no_args) no longer triggers an error.

Sadly, it doesn't work in MSVC2017, but is fixed in latest preview of MSVC2019.

And this solution is somewhat clumsy. I tried to think about different solution, something like

#define EXTRACT_FIRST(_1, ...) _1
#define OMIT_FIRST(_1, ...) __VA_ARGS__
#define METHOD_DECL(ret, ...) ret EXTRACT_FIRST(__VA_ARGS__) OMIT_FIRST(__VA_ARGS__)

But this just moved the problem, since now OMIT_FIRST triggers this error

EDIT:
What I am trying to do is following:

I have function in AVR assembler (micro-controler)

delay_37us:
    ldi r16, 227
delay_592c_aw:
    dec r16
    brne delay_592c_aw
    nop
    nop
    ret

That active waits for 592cycles (which is 37us for 16MHz cpu)

In order to call this function in C, I have to mark it as .global and also provide C declaration of such function. In order to simplify declaration of such function I would use a macro like that

FUNCTION_DECL(void, delay_37us);

which would be defined as

#ifdef __ASSEMBLER__
  #define FUNCTION_DECL(ret, name, ...) .global name
#else
  #define FUNCTION_DECL(ret, name, ...) ret name(__VA_ARGS__)
#endif

So that I could use one header file for both C and ASM. What I am using currently is one header file with following content

#ifdef __ASSEMBLER__
  .global delay_37us
  .global delay_ms
  .global delay_1s
#else
  void delay_37us();
  void delay_ms(unsigned char);
  void delay_1s();
#endif

Which is error-prone to maintain.

Zereges
  • 5,139
  • 1
  • 25
  • 49
  • 2
    I would argue that the "universal way" is to *not use macros* to begin with. What is the *actual* problem you're trying to solve my your `FUNCTION_DECL` macro? – Some programmer dude Dec 08 '18 at 10:21
  • @Someprogrammerdude Mixing C and assembler for AVR microcontrolers (having common header file for functions *exported* by assembler and used in C or viceversa). Something like [that](https://pastebin.com/Kau1Tb19) – Zereges Dec 08 '18 at 10:28
  • Those tricks are always ugly and if you care about readability, you end up using [variadic functions](https://en.wikipedia.org/wiki/Variadic_function#Example_in_C) – David Ranieri Dec 08 '18 at 10:41
  • @KeineLust I edited my question so that the intent is clearly visible. – Zereges Dec 08 '18 at 11:09
  • I think it is futile to try to cicrumvent this C++ restriction. You could look at argument counting macros (like [https://stackoverflow.com/questions/53159137/what-are-the-deviations-between-preprocessors-of-gcc-clang-vs-msvc]) but I think this won't make the warning go away, as all techniques are relying on empty parameter places. This surely is a point where the standard runs against living and working enigneering practice. – Vroomfondel Dec 13 '18 at 14:20
  • The subject says ISO C99, the warning says ISO C++11, and the text itself talks about C programming. Which is it, C or C++? The empty argument list `foo()` means very different things in them. In C, you should use `foo(void)`, and in C++ you can use it. It conveniently also solves the problem for you, while technically not answering the question about variadic args. – Jani Jan 04 '19 at 13:14

0 Answers0