18

Can we specify default parameter values for macro parameters?

I know there isn't any type-checking, so I expect the default value to be nothing more than just some text used by the preprocessor for macro expansion in instances where the parameter value is not specified.

6
  • @2501 I believe the answer is effectively the same but they are not exact duplicates Commented Nov 20, 2014 at 21:11
  • No. Anyway, the preprocessor is complicated enough as it is ;-) Commented Nov 20, 2014 at 21:14
  • 3
    I think this is what you're looking for : Default arguments for C99 Commented Nov 20, 2014 at 21:26
  • Are you trying to use macro to avoid changing the code completely or are you going to edit every call anyway? Commented Nov 20, 2014 at 21:41
  • 1
    See also stackoverflow.com/q/25848461/1366431 Commented Nov 20, 2014 at 21:53

3 Answers 3

23

You are looking for a macro overload mechanism which is provided in e.g. Boost.PP's facilities.

#define MACRO_2(a, b) std::cout << a << ' ' << b;

#define MACRO_1(a) MACRO_2(a, "test") // Supply default argument

// Magic happens here:

#define MACRO(...) BOOST_PP_OVERLOAD(MACRO_, __VA_ARGS__)(__VA_ARGS__)

Demo. The number of arguments is concatenated with the macro name, which can easily be implemented without Boost as follows:

#define VARGS_(_10, _9, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N 
#define VARGS(...) VARGS_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)

#define CONCAT_(a, b) a##b
#define CONCAT(a, b) CONCAT_(a, b)

And

#define MACRO_2(a, b) std::cout << a << ' ' << b;

#define MACRO_1(a) MACRO_2(a, "test") // Supply default argument

#define MACRO(...) CONCAT(MACRO_, VARGS(__VA_ARGS__))(__VA_ARGS__)

Demo.

Sign up to request clarification or add additional context in comments.

Comments

8

There is a way to do it, if you permit an unusual syntax:

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

void TestInternal( int n )
{
    printf("%d\n" , n ) ;
}
#define TestGet( f , ... )  f
#define Test( ... ) TestInternal( TestGet( __VA_ARGS__ DEFAULT , DEFAULT ) )
#define DEFAULT 100

int main( void )
{ 
    Test( ) ;
    Test( 12345 , ) ;

return 0 ;
}

This is type safe and can be expanded to any number of arguments.

Note that the comma must be present if you pass a variable. You can treat it as an indicator that this function/macro has default parameters.

Using a similar version you can omit the comma, but then your functions must have at least one non-default parameter which must be first.

Comments

2

It seems like the simplest solution is to define an additional macro that is missing the default parameter.

#define MACRO1( PARAM1 , PARAM2 ) &( PARAM1 + PARAM2 ) // or whatever logic

#define MACRO1_DEFAULT( PARAM1 ) MACRO1 ( PARAM1 , 12 ) // PARAM2 default of 12

Also, as mentioned by 40two, the language does support using an ellipsis for variadic macros, which may also be a viable solution in some instances.

Contents of the linked article:

Variadic macros are function-like macros that contain a variable number of arguments.

To use variadic macros, the ellipsis may be specified as the final formal argument in a macro definition, and the replacement identifier __VA_ARGS__ may be used in the definition to insert the extra arguments.
__VA_ARGS__ is replaced by all of the arguments that match the ellipsis, including commas between them.

The C Standard specifies that at least one argument must be passed to the ellipsis, to ensure that the macro does not resolve to an expression with a trailing comma.

<Microsoft specific>
The Visual C++ implementation will suppress a trailing comma if no arguments are passed to the ellipsis.
</Microsoft Specific>

Example

// variadic_macros.cpp
#include <stdio.h>
#define EMPTY

#define CHECK1(x, ...) if (!(x)) { printf(__VA_ARGS__); }
#define CHECK2(x, ...) if ((x)) { printf(__VA_ARGS__); }
#define CHECK3(...) { printf(__VA_ARGS__); }
#define MACRO(s, ...) printf(s, __VA_ARGS__)

int main() {
    CHECK1(0, "here %s %s %s", "are", "some", "varargs1(1)\n");
    CHECK1(1, "here %s %s %s", "are", "some", "varargs1(2)\n");   // won't print

    CHECK2(0, "here %s %s %s", "are", "some", "varargs2(3)\n");   // won't print
    CHECK2(1, "here %s %s %s", "are", "some", "varargs2(4)\n");

    // always invokes printf in the macro
    CHECK3("here %s %s %s", "are", "some", "varargs3(5)\n");

    MACRO("hello, world\n");

    MACRO("error\n", EMPTY); // would cause error C2059, except VC++ 
                             // suppresses the trailing comma
}

Output

here are some varargs1(1)
here are some varargs2(4)
here are some varargs3(5)
hello, world
error

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.