8

Is it possible to implement a macro conditional inside a macro function in C. Something like this:

#define fun(x)
#if x==0
    fun1;
#else
    fun2;
#endif

#define fun1 // do something here
#define fun2 // do something else here

In other words, preprocessor decides which macro to use based on an argument value.

fun(0) // fun1 is "preprocessed"
fun(1) // fun2 is "preprocessed"

I know that this example doesn't work, but I want to know is it possible to make it work somehow?

M.

Marko Gulin
  • 509
  • 3
  • 6
  • 19
  • 1
    The pre-processor "modifies" the code *even before compilation*, so at runtime is definitely settled. – alk Dec 03 '16 at 12:37
  • 2
    Yes, I know that. But `x` is not a variable, it's value is known before compilation. – Marko Gulin Dec 03 '16 at 12:39
  • [BOOST_PP_IF](http://www.boost.org/doc/libs/1_55_0/libs/preprocessor/doc/ref/if.html) (or IIF) – BLUEPIXY Dec 03 '16 at 12:40
  • I don't think that's possible. The C preprocessor is pretty limited in its functionality. I like to use GNU m4, which is very powerful. Unfortunately, its development is somehow stuck, I don't know about future releases (if there ever will be one). With cpp, I'd just define a value `x` as you did, but put the conditional directives outside of a macro. – cadaniluk Dec 03 '16 at 12:43

1 Answers1

11

You cannot use pre-processor conditionals inside a pre-processor directive. Background and workarounds you find for example here: How to use #if inside #define in the C preprocessor? and Is it possible for C preprocessor macros to contain preprocessor directives?

Still, you could do:

#include <stdio.h>

#define CONCAT(i) fun ## i() /* For docs on this see here:
                                https://gcc.gnu.org/onlinedocs/cpp/Concatenation.html */
#define fun(i) CONCAT(i)

void fun1(void)
{
  puts(__FUNCTION__);
}

void fun2(void)
{
  puts(__FUNCTION__);
}


int main(void)
{
  fun(1);
  fun(2);
}

This would result in:

...

int main(void)
{
  fun1();
  fun2();
}

being passed to the compiler and print:

fun1
fun2

You could obfuscate your code even more by doing for example:

... 

#define MYZERO 1
#define MYONE 2

int main(void)
{
  fun(MYZERO);
  fun(MYONE);
}

resulting in the same code being passed to the compiler.

alk
  • 69,737
  • 10
  • 105
  • 255
  • 1
    Upvoted and deleted my answer, but it would be useful (for others) to explain why `#if` 'inside' `#define` doesn't work. – abligh Dec 03 '16 at 12:50
  • Good solution, but why on earth is your token-pasting macro named "stringify" ? ;) – Quentin Dec 03 '16 at 13:04
  • @Quentin: Hu, habbits and patterns ... :} fixing this. – alk Dec 03 '16 at 13:06
  • Dear alk, thank you for your answers. I have one more question regarding macros. Is it possible to get something like this - Macro function is called as `macro_fun(7)`, and the output is `AD1`. In other words, I want to evaluate `7-6`, and to concatenate the result as a token, e.g. `AD ## x-6`. I know that this example doesn't work, but can I make it work somehow? – Marko Gulin Dec 03 '16 at 13:57
  • @Marko: I am not aware that the pre-processor does any arithmetics, will say evaluates 3-2 to 1 or such. Perhaps you want to read on functions-pointers and handle all this mapping at run-time in C. – alk Dec 03 '16 at 14:05
  • @abligh I suspect this is because the `#if`-statement is evaluated when the macro is defined and not when the macro is called. – HelloGoodbye Dec 22 '17 at 15:19