Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using defined(MACRO) inside the C if statement

I would like to write code in C something like this:

if(defined(MACRO))
  ...
else
  ...

but I could not find any way to do this in C, since the defined(MACRO) preprocessor operator works only inside #if's. Is there a way to do this?

What I really like to do is to write:

ASSERT(UART, var >= 0);

where

#define ASSERT(NAME, TEST) \
  do { \
    if (defined(NAME) && !(TEST)) \
      printf("Assert failed"); \
  } while(0)

thus I could turn on ASSERT checks when a macro is defined and if it is not defined, then the asserts should not be checked. If you try to do this, then you get:

implicit declaration of function `defined'

which is quite understandable since the GCC compiler does not find the defined() preprocessor operator.

like image 415
Miklos Maroti Avatar asked Mar 28 '11 19:03

Miklos Maroti


2 Answers

A macro by comex is expanded to 1 if the argument is defined to 1. Otherwise it is expanded to 0:

#define is_set(macro) is_set_(macro)
#define macrotest_1 ,
#define is_set_(value) is_set__(macrotest_##value)
#define is_set__(comma) is_set___(comma 1, 0)
#define is_set___(_, v, ...) v

You can use it as follows:

if (is_set(MACRO)) {
   /* Do something when MACRO is set */
}

Explanation: The trick is based on variadic function-like macros (...) and preprocessor token concatenation (##).

  1. is_set is simply a wrapper to facilitate the expansion of its parameter.
  2. is_set_ tries to concatenate macrotest_ with the evaluated value of its input (comma). If its input is defined, then this works; otherwise is_set__ is called with macrotest_<macro> where <macro> is the original argument to is_set (e.g., is_set(foo) leads to macrotest_foo if foo is not a defined macro).

  3. In is_set__ its parameter is again expanded but this only works out if it is passed macrotest_1. If it is, then is_set___(, 1, 0) is called because comma evaluates to , (note the 3 parameters!). For any other value of comma (i.e., if the macro to be tested is undefined or has any other (expanded) value than 1 the parameter can not be expanded and thus is_set___(macrotest_<macro> 1, 0) is called, which has only 2 arguments.

  4. Eventually, is_set___ simply selects its second parameter for its "output" and drops everything else. Due to the behavior of is_set__ this leads to either 1 if the macro to be tested is defined and 1, or 0 otherwise.

like image 64
vitaut Avatar answered Sep 22 '22 19:09

vitaut


Ok, based on the previous post I got this idea, which seems to work:

#define DEFINEDX(NAME) ((#NAME)[0] == 0)
#define DEFINED(NAME) DEFINEDX(NAME)

This will check if NAME is defined and therefore it expands to the empty string with 0 at its first character, or it is undefined in which case it is not the empty string. This works with GCC, so one can write

if( DEFINED(MACRO) )
  ...
like image 23
Miklos Maroti Avatar answered Sep 23 '22 19:09

Miklos Maroti