207

I want to write a macro in C that accepts any number of parameters, not a specific number

example:

#define macro( X )  something_complicated( whatever( X ) )

where X is any number of parameters

I need this because whatever is overloaded and can be called with 2 or 4 parameters.

I tried defining the macro twice, but the second definition overwrote the first one!

The compiler I'm working with is g++ (more specifically, mingw)

a3f
  • 7,797
  • 1
  • 33
  • 39
hasen
  • 148,751
  • 62
  • 182
  • 223
  • 8
    Do you want C or C++? If you're using C, why are you compiling with a C++ compiler? To use proper C99 variadic macros, you should be compiling with a C compiler that supports C99 (like gcc), not a C++ compiler, since C++ doesn't have standard variadic macros. – Chris Lutz Mar 25 '09 at 02:13
  • Well, I assumed C++ is a super set of C in this regard .. – hasen Mar 25 '09 at 03:46
  • http://tigcc.ticalc.org/doc/cpp.html#SEC13 has a detailed explanation of variadic macros. – Gnubie Oct 25 '11 at 09:49
  • 1
    A good explanation and example is here [http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html](http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html) – zafarulq Apr 11 '13 at 06:41
  • 3
    For future readers: C is **not** a subest of C++. They share many many things, but there are rules that stop them being subset and superset of each other. – Pharap Sep 09 '17 at 00:28

5 Answers5

311

C99 way, also supported by VC++ compiler.

#define FOO(fmt, ...) printf(fmt, ##__VA_ARGS__)
Alex B
  • 75,980
  • 39
  • 193
  • 271
  • 9
    I don't think C99 requires the ## before __VA_ARGS__. That might just be VC++. – Chris Lutz Mar 25 '09 at 02:18
  • 102
    The reason for ## before __VA_ARGS__ is that it swallows the preceding comma in case the variable-argument list is empty, eg. FOO("a") expands to printf("a"). This is an extension of gcc (and vc++, maybe), C99 requires at least one argument to be present in place of the ellipsis. – jpalecek Mar 26 '09 at 20:20
  • 115
    `##` is not needed and is not portable. `#define FOO(...) printf(__VA_ARGS__)` does the job the portable way; the `fmt` parameter can be omitted from the definition. – alecov Jun 11 '12 at 20:14
  • 4
    IIRC, the ## is GCC specific and allows passing of zero parameters – Mawg says reinstate Monica Jul 23 '12 at 04:28
  • 2
    What if you wanted to consume those arguments in the macro and without using printf or other functions that take variable args? – jjxtra Apr 11 '13 at 16:40
  • @Alek: If I use the portable FOO(...) printf(__VA_ARGS__) you suggest above, how would one add a "\n" except writing it in the macro call FOO("My string here\n")? – uniquenamehere Jan 18 '14 at 15:34
  • 11
    The ##-syntax works also with llvm/clang and the Visual Studio compiler. So it might not be portable, but it is supported by the major compilers. – K. Biermann Dec 17 '14 at 21:13
  • @jjxtra I imagine you would need to pass them to one of your own functions that takes variable params. – Dennis Apr 05 '16 at 17:03
  • 1
    @K.Biermann Even for compilers that **do** support `##`, if there's no comma *immediately before* the `##` in the macro, the `##` will try to *paste tokens together*, which is almost never the right behavior. – Kyle Strand Jul 28 '16 at 16:38
39

__VA_ARGS__ is the standard way to do it. Don't use compiler-specific hacks if you don't have to.

I'm really annoyed that I can't comment on the original post. In any case, C++ is not a superset of C. It is really silly to compile your C code with a C++ compiler. Don't do what Donny Don't does.

cmccabe
  • 3,742
  • 1
  • 21
  • 10
  • 9
    *"It is really silly to compile your C code with a C++ compiler"* => Not considered so by everyone (including me). See for instance C++ core guidelines: **CPL.1: Prefer C++ to C** , [**CPL.2: If you must use C, use the common subset of C and C++, and compile the C code as C++**](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rcpl-subset). I'm hard-pressed to think of what "C-only-isms" one really needs to make it worth not programming in the compatible subset, and the C and C++ committees have worked hard on making that compatible subset available. – HostileFork says dont trust SE May 18 '16 at 07:02
  • 4
    @HostileFork Fair enough, though *of course* the C++ folks would like to encourage use of C++. Others do disagree, though; Linux Torvalds, for instance, has apparently rejected multiple proposed Linux-kernel patches that attempt to replace the identifier `class` with `klass` to permit compiling with a C++ compiler. Also note that there are some differences that will trip you up; for instance, the ternary operator is not evaluated in the same way in both languages, and the `inline` keyword means something completely different (as I learned from a different question). – Kyle Strand Jul 28 '16 at 16:44
  • 3
    For really cross-platform systems projects like an operating system, you really want to adhere to strict C, because C compilers are so much more common. In embedded systems, there are still platforms without C++ compilers. (There are platforms with only passable C compilers!) C++ compilers make me nervous, particularly for cyber-physical systems, and I would guess I'm not the only embedded software / C programmer with that feeling. – downbeat May 16 '17 at 15:30
  • 3
    @downbeat Whether you use C++ for production or not, if it's rigor you are concerned about, then being able to compile with C++ gives you magic powers for static analysis. If you have a query you want to make of a C codebase...wondering about if certain types are used certain ways, learning how to use [type_traits](https://en.cppreference.com/w/cpp/header/type_traits) can build targeted tools for it. What you'd pay big bucks for a static analysis tool of C to do can be done with a bit of C++ know how and the compiler you already have... – HostileFork says dont trust SE Jul 27 '18 at 19:57
  • 1
    I'm speaking to the question of Linux. (I just noticed that it says "Linux Torvalds" ha!) – downbeat Jul 29 '18 at 03:05
  • There's nothing "magic" about type_traits. C has similar stuff, such as "typeof." Yes, technically it is a compiler extension, but both gcc and clang support it. Neither typeof nor type_traits are replacements for static analysis tools (many of which are free – cmccabe Jul 29 '18 at 05:41
29

I don't think that's possible, you could fake it with double parens ... just as long you don't need the arguments individually.

#define macro(ARGS) some_complicated (whatever ARGS)
// ...
macro((a,b,c))
macro((d,e))
eduffy
  • 35,646
  • 11
  • 90
  • 90
10
#define DEBUG

#ifdef DEBUG
  #define PRINT print
#else
  #define PRINT(...) ((void)0) //strip out PRINT instructions from code
#endif 

void print(const char *fmt, ...) {

    va_list args;
    va_start(args, fmt);
    vsprintf(str, fmt, args);
        va_end(args);

        printf("%s\n", str);

}

int main() {
   PRINT("[%s %d, %d] Hello World", "March", 26, 2009);
   return 0;
}

If the compiler does not understand variadic macros, you can also strip out PRINT with either of the following:

#define PRINT //

or

#define PRINT if(0)print

The first comments out the PRINT instructions, the second prevents PRINT instruction because of a NULL if condition. If optimization is set, the compiler should strip out never executed instructions like: if(0) print("hello world"); or ((void)0);

jpalecek
  • 44,865
  • 7
  • 95
  • 139
  • 8
    #define PRINT // will not replace PRINT with // – bitc Jun 16 '10 at 07:48
  • 8
    #define PRINT if(0)print is not a good idea either because the calling code might have its own else-if for calling PRINT. Better is: #define PRINT if(true);else print – bitc Jun 16 '10 at 07:58
  • 3
    The standard "do nothing, gracefully" is do {} while(0) – vonbrand Nov 05 '14 at 14:23
  • The proper `if` version of "don't do this" that takes code structure into account is: `if (0) { your_code } else` a semi-colon after your macro expansion terminates the `else`. The `while` version looks like: `while(0) { your_code }` The issue with the `do..while` version is that the code in `do { your_code } while (0)` is done once, guaranteed. In all three cases, if `your_code` is empty, it is a proper `do nothing gracefully`. – Jesse Chisholm Dec 14 '15 at 19:27
7

explained for g++ here, though it is part of C99 so should work for everyone

http://www.delorie.com/gnu/docs/gcc/gcc_44.html

quick example:

#define debug(format, args...) fprintf (stderr, format, args)
DarenW
  • 15,697
  • 7
  • 59
  • 96