Home > Net >  NOT accepting variables as an argument in a macro
NOT accepting variables as an argument in a macro

Time:07-10

I want to reduce the chance of mistakes by other developers and I am looking for a solution for limiting the input of macro definition to NOT accept variables as an input.

#define TIMEFRAME_MILISEC(X)        ((X))
#define TIMEFRAME_SECONDS(X)        ((X) * TIMEFRAME_MILISEC(1000))
#define TIMEFRAME_MINUTES(X)        ((X) * TIMEFRAME_SECONDS(60))
#define TIMEFRAME_HOURS(X)          ((X) * TIMEFRAME_MINUTES(60))

The usual mistake is that the definition is used for the initialization of variables value and after that calling the definition with the variable again. I just want to be used with "hardcoded" values.

TIMEFRAME_SECONDS(5)

CodePudding user response:

You could create a dirty trick macro such as this:

#define ASSERT_INTCONST(X)  ( (int[X]){0} )
  • In case X is an integer constant expression, this will create a temporary compound literal, which we will discard/optimize out.
  • In case X is a variable expression, there will be a compiler error since compound literals aren't allowed to be of variable length.

Example:

#define ASSERT_INTCONST(X) ( (int[X]){0} )
#define TIMEFRAME_MILISEC(X)  ( ASSERT_INTCONST(X), (X) )
#define TIMEFRAME_SECONDS(X)  ( ASSERT_INTCONST(X), (X) * TIMEFRAME_MILISEC(1000))
#define TIMEFRAME_MINUTES(X)  ( ASSERT_INTCONST(X), (X) * TIMEFRAME_SECONDS(60))
#define TIMEFRAME_HOURS(X)    ( ASSERT_INTCONST(X), (X) * TIMEFRAME_MINUTES(60))

int main (void)
{
  int x = TIMEFRAME_SECONDS(3); // ok
  int y=3;
  int z = TIMEFRAME_SECONDS(y); // error: compound literal has variable size
}

For further type safety such as only allowing certain integer types:

#define ASSERT_INTCONST(X) ( (int[X]){ _Generic((X),int:0) } )

Now only integer constant expressions of type int will get let through. Not long, unsigned int, size_t etc.

  • Related