2

I have a macro for checking results of some test methods:

#define Eval(func, ...) if (func == -1) { printf(__VA_ARGS__); return -1; }

I want to get this functionally:

Eval(Check_1(),"Check1 failed."); // case 1
Eval(Check_2()); // case 2
Eval(Check_3(), "some variable=%i", variableValue); // case 3

At case 1 I want to write comment to user ("Check1 failed") and then return -1 (it's work). At case 2 I just want to return from method, not print any information for user. So I must to detect situation of empty comment and not to call printf() - it's not work.

If any of "Check_x" methods failed, i need exit from current method by return code -1;

Is it any way to do this with macro?

Very similar question was here: Standard alternative to GCC's ##VA_ARGS trick? , but I can't modify this code for my situation.

EDIT: I use C99 standart. At current version of my code case 2 compiled with error "expected an expression" (I think it because of comma and empty argument). Also I need to use case 3 for print additional information (variable values). So, second argument not actually simple string.

EDIT2: I get solution for my task. Here I find it

// Macro to count of arguments
#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, 10,9,8,7,6,5,4,3,2,1)
#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,N,...) N

// Macro dispatcher
#define macro_dispatcher(func, ...) macro_dispatcher_(func, VA_NUM_ARGS(__VA_ARGS__))
#define macro_dispatcher_(func, nargs) macro_dispatcher__(func, nargs)
#define macro_dispatcher__(func, nargs) func ## nargs

#define EVAL_UNIVERSAL(...) macro_dispatcher(EV, __VA_ARGS__)(__VA_ARGS__)

#define EV1(func) if (func == -1) return -1;
#define EV2(func, ...) if (func == -1) { printf(__VA_ARGS__); return -1; }

#define EV3(func, ...) EV2(func, __VA_ARGS__)
#define EV4(func, ...) EV2(func, __VA_ARGS__)
#define EV5(func, ...) EV2(func, __VA_ARGS__)
#define EV6(func, ...) EV2(func, __VA_ARGS__)
#define EV7(func, ...) EV2(func, __VA_ARGS__)

And I use it like this:

EVAL_UNIVERSAL(CheckInitialParameters());
EVAL_UNIVERSAL(CheckInitialParameters(), "text");
EVAL_UNIVERSAL(CheckInitialParameters(), "%i", 1);
EVAL_UNIVERSAL(CheckInitialParameters(), "%i %i", 1, 2);

Very thanks to Jens Gustedt, and rmn (http://efesx.com/)

Community
  • 1
  • 1
  • 3
    If you restrict the first (optional) parameter to literal string you may change `printf(__VA_ARGS__)` to `printf("" __VA_ARGS__)` and let concatenation do the job. – Jarod42 Feb 17 '16 at 13:12
  • Else, in c++11, you may forward to variadic template function. – Jarod42 Feb 17 '16 at 13:13
  • What's wrong with your current code? It looks OK to me. – GingerPlusPlus Feb 17 '16 at 13:17
  • What is the compiler? Do you use C++11? – user3159253 Feb 17 '16 at 13:23
  • Jarod42, very interesting idea! Maybe I can write first macro to convert ("some variable=%i", variableValue) to string and then pass it to my macro Eval. I believe that solution is very close. – Mihail Isaev Feb 18 '16 at 06:41
  • So what do you use, C or C++? These are two different languages, and in particular they may differ on the level of the preprocessor. – Jens Gustedt Feb 18 '16 at 07:38
  • I use both C and C++ in my project. It's project of embedded software in Keil uVision IDE ARM. But this macro I will use only in C++ files. – Mihail Isaev Feb 18 '16 at 07:57
  • Then the C preprocessor is not the right tool for you. Distinguish C++ and C and use the appropriate tools. – Jens Gustedt Feb 18 '16 at 08:24

1 Answers1

2
// Macro to count of arguments
#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, 10,9,8,7,6,5,4,3,2,1)
#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,N,...) N

// Macro dispatcher
#define macro_dispatcher(func, ...) macro_dispatcher_(func, VA_NUM_ARGS(__VA_ARGS__))
#define macro_dispatcher_(func, nargs) macro_dispatcher__(func, nargs)
#define macro_dispatcher__(func, nargs) func ## nargs

#define EVAL_UNIVERSAL(...) macro_dispatcher(EV, __VA_ARGS__)(__VA_ARGS__)

#define EV1(func) if (func == -1) return -1;
#define EV2(func, ...) if (func == -1) { printf(__VA_ARGS__); return -1; }

#define EV3(func, ...) EV2(func, __VA_ARGS__)
#define EV4(func, ...) EV2(func, __VA_ARGS__)
#define EV5(func, ...) EV2(func, __VA_ARGS__)
#define EV6(func, ...) EV2(func, __VA_ARGS__)
#define EV7(func, ...) EV2(func, __VA_ARGS__)

And I use it like this:

EVAL_UNIVERSAL(CheckInitialParameters());
EVAL_UNIVERSAL(CheckInitialParameters(), "text");
EVAL_UNIVERSAL(CheckInitialParameters(), "%i", 1);
EVAL_UNIVERSAL(CheckInitialParameters(), "%i %i", 1, 2);