Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a macro that can omit a line based on a parameter

I have the following lines of code, created by a database export program:

typedef struct _s8_VARB
{
    unsigned char _byte[8];
} s8_VARB;

const s8_VARB varb00[] = {
    mMM(1,25,22,12,0,0,0,0,27)
    mMM(0,1,29,12,0,0,0,0,21)
    mMM(1,1,36,12,0,0,0,0,22)
}

The mMM is a macro that I want to define with a functionality that will produce the following data during compilation:

const s8_VARB varb00[] = {
    1,25,22,12,0,0,0,0,27,
    1,1,36,12,0,0,0,0,22,
}

So it basically should check the 1st parameter. If it is 0, that complete line should omitted. If it is 1, all the parameters (except the 1st) should be 'put on the line', ending with a comma.

What I have tried is this:

#define COMMA ,
#define mMM(cond, a,b,c,d,e,f,g,h)  (cond) ? (a),(b),(c),(d),(e),(f),(g),(h) COMMA :

But this is not working. Not even compiling, as gcc complains:

error: expected expression before ':' token

How should this macro definition should look like? Is this possible at all in C?

like image 531
user2448122 Avatar asked Dec 24 '22 21:12

user2448122


2 Answers

You can initialize an array with constant data only. A conditional statement is by definition not constant (even if it's known to the compiler at compile time).

Instead you could do it like this:

#define _mMM0(...)
#define _mMM1(...)  {__VA_ARGS__},
#define mMM(cond, ...) _mMM##cond(__VA_ARGS__)

const unsigned char varb00[][8] = {
      mMM(1,25,22,12,0,0,0,0,27)
      mMM(0,1,29,12,0,0,0,0,21)
      mMM(1,1,36,12,0,0,0,0,22)
};

I removed the struct and replaced it with its only member directly. In case C99 is not available, you can name every parameter as you used to do.

like image 71
a3f Avatar answered Feb 14 '23 12:02

a3f


Here's a hackish solution. If the number of arguments is fixed and you can't use C99+, then you could list them explicitly instead of using ... and __VA_ARGS__.

#define mMM(x, ...) mMM##x(__VA_ARGS__)
#define mMM0(...)
#define mMM1(...) __VA_ARGS__,

The ## operator pastes the token mMM and the x argument together to form a new macro name -- either mMM0 or mMM1 -- which is then called with the remaining arguments. mMM0() in turn expands to nothing, and mMM1() expands to its arguments.

(The extra trailing comma after the last element won't be a problem by the way. int a[] = { 1, 2, 3, } is explicitly allowed syntax in C.)

As a side note, invoking a macro like

#define m(x) (x) ? 1 : 2

using e.g. m(0) will simply expand it to (0) ? 1 : 2. The ternary operator will not be handled in the preprocessor.

like image 36
Ulfalizer Avatar answered Feb 14 '23 10:02

Ulfalizer