Grigorii Alekseev
Grigorii Alekseev

Reputation: 177

How to create macro with different behavior depending on parameters number?

I want to create one macro that will work differently in case when it HAS parameters or NOT.

For example: there are two different implementation of printing error:

// 1. Print message = check code
#define PRINT_IF(wasError) \
    do { if (wasError) printf(#wasError); } while(false)

// 2. Throws an exception with formatted message
#define PRINT_TEXT_IF(wasError, format, ...) \
    do { if (wasError) printf(format, ##__VA_ARGS__); } while(false)

And I'd like to have one macro for both cases.

What I've tried is create a global macro that checks if it has parameter or not, based on approach from How to count the number of arguments passed to a function that accepts a variable number of arguments?.

#define RANDOM_GUID "5c300a82-2fe8-4bd3-ad12-ef13fa7b4a82"
#define FIRST_ARG(a1, ...) a1
#define HAS_ARGS(...) FIRST_ARG(##__VA_ARGS__, RANDOM_GUID)

#define GLOBAL_PRINT_IF(wasError, ...)             \
    do {                                           \ 
      if (wasError) {                              \
        if (HAS_ARGS(##__VA_ARGS__)==RANDOM_GUID ) \
          PRINT_IF(wasError);                      \
        else                                       \
          PRINT_TEXT_IF(wasError, __VA_ARGS__);    \
      }                                            \
    } while(false)

I assume that because FIRST_ARG always return first argument, it will return RANDOM_GUID if ##__VA_ARGS__ are empty.

But this code doesn't compile with error: pasting "." and "red" does not give a valid preprocessing token. I've tried to play with ## before __VA_ARGS__, but it fails with expected primary-expression before ‘==’ token in line

if (HAS_ARGS(__VA_ARGS__)==RANDOM_GUID )

So, what am I doing wrong? How to deal with it properly?

Upvotes: 1

Views: 642

Answers (1)

Guillaume D
Guillaume D

Reputation: 2326

  1. Start by looking how to get the number of argument in a variadic macro here
  2. Then when you know how to get the number of argument, you can easily check if this number is 0.

And this snippet returns the number of argument event if this is 0:

#include <stdio.h>

#define PRINT(...)  (printf("%d\n", sizeof((int[]){__VA_ARGS__})/sizeof(int)))

int main(void)
{
    PRINT();
    PRINT(1,1);
    PRINT(1,1,1,1);
    return 0;
}

so easily, this second snippet does the job

#include <stdio.h>

#define PRINT(...)  (((sizeof((int[]){__VA_ARGS__})/sizeof(int))==0)?printf("do A\n"):printf("do B\n"))

int main(void)
{
    PRINT();
    PRINT(1,1);
    PRINT(1,1,1,1);
    return 0;
}

Upvotes: 1

Related Questions