248

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)

6
  • 11
    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. Commented Mar 25, 2009 at 2:13
  • Well, I assumed C++ is a super set of C in this regard .. Commented Mar 25, 2009 at 3:46
  • tigcc.ticalc.org/doc/cpp.html#SEC13 has a detailed explanation of variadic macros. Commented Oct 25, 2011 at 9:49
  • 1
    A good explanation and example is here http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html Commented Apr 11, 2013 at 6:41
  • 6
    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. Commented Sep 9, 2017 at 0:28

6 Answers 6

366

C99 way:

#define FOO(...) printf(__VA_ARGS__)
Sign up to request clarification or add additional context in comments.

9 Comments

I don't think C99 requires the ## before VA_ARGS. That might just be VC++.
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.
## 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.
IIRC, the ## is GCC specific and allows passing of zero parameters
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.
|
53

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

C++ is not a superset of C. It is really silly to compile your C code with a C++ compiler.

7 Comments

"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++. 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 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).
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 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 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...
I'm speaking to the question of Linux. (I just noticed that it says "Linux Torvalds" ha!)
|
32

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

2 Comments

While it is possible to have a variadic macro, using double parenthesis is a good advice.
The XC compiler by Microchip does not support variadic macros, and so this double parenthesis trick is the best you can do.
13
#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);

4 Comments

#define PRINT // will not replace PRINT with //
#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
The standard "do nothing, gracefully" is do {} while(0)
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.
10

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)

6 Comments

GCC's variadic macros are not C99 variadic macros. GCC has C99 variadic macros, but G++ doesn't support them, because C99 is not part of C++.
Actually g++ will compile C99 macros in C++ files. It will issue a warning, however, if compiled with '-pedantic'.
It is not C99. C99 use VA_ARGS macro).
C++11 also supports __VA_ARGS__, although they are supported by compilers in earlier versions as well, as an extension.
This fails to work for printf("hi"); where there are no var args. Any generic way to fix this?
|
1

• Variable number of arguments is denoted by an ellipsis (...) • The syntax of ISO C requires at least one fixed argument before the ‘...’

For example, you can type:

#define DEBUGMSG ( int, ...)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.