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

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?

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.

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.

Related

C preprocessor #if condition

I am building some generic things in C.
Here is the code:
// main.c
#include <stdio.h>
#define T int;
#include "test.h"
int main()
{
return 0;
}
// test.h
#define _array_is_pointer(T) ( \
{ \
T _value; \
__builtin_classify_type(_value) == 5; \
})
#ifdef T
#if _array_is_pointer(T)
struct array_s
{
T *items;
}
void array_push(struct array_s * array, T value)
{
// push method for pointer.
}
#else
struct array_s
{
T *items;
}
void array_push(struct array_s * array, T value)
{
// push method for non-pointer.
}
#endif
#endif
** edited: add more code in test.h **
I would like the preprocessor runs different code when T is pointer or non-pointer.
But I got an error token "{" is not valid in preprocessor expressions.
Is it possible to do that?
I would like the preprocessor runs different code when T is pointer or non-pointer.
Is it possible to do that?
No, it is not possible. Preprocessor is not aware of types.
If you really want this, pass a mark if T is a pointer or not as a separate macro.
#define T int*
#define T_IS_A_POINTER 1
#include "test.h"
Or have separate calls:
#define T int*
#include "test_a_pointer.h"
#define T int
#include "test_not_a_pointer.h"
The preprocessor doesn't know whether T is a pointer, because preprocessing happens before semantic analysis of the program. All the preprocessor sees are tokens; it knows that 42 is a number and take42, but that's it. The only definitions it knows about are preprocessor #defines.
Moreover, in C, functions --even builtin constant functions like sizeof and __builtin_classify_type-- cannot be evaluated by the preprocessor. The preprocessor cannot evaluate block expressions either, but there wouldn't be much point so it has no idea what a variable is and thus doesn't need declarations. The only identifier you can use in an #if preprocessor conditional are macro definitions which expand to integer constants (or entire expressions containing only arithmetic operations on integer constants).
There is the _Generic construct introduced in C11, which allows you to generate different expressions based on the type of a controlling expression. But it can only be used to generate expressions, not declarations, so it's probably not much help either.
There is no issue while writing multi-line code-snippet in
#define _array_is_pointer(T) ( \
{ \
T _value; \
__builtin_classify_type(_value) == 5; \
})
But, as you have know, the first step done before passing the code to compiler is to create an Expanded source code. In this step, all the five lines woud be pasted whereever you would have written _array_is_pointer(T) and hence resulting code would have :
#if (
{
T _value;
__builtin_classify_type(_value) == 5;
})
and here is a blunder. One can not write multiple lines like this in if clause, nor you could do this using {}. And hence, you got the error token "{" is not valid in preprocessor expressions.
Hence, you would have to write a single expression to in if clause preprocessor.

Macro inside enum in C

While trying to write a macro inside an enum, in C.
We have to sometimes write name of macro, above macro definition, why ?
#include <stdio.h>
enum month {
MSD //If I remove or comment this line, code does not work, why?
#define MSD 7
};
void main() {
printf("%d\n", MSD);
}
If we remove the 5th line of code, i.e. "MSD". We get error
empty enum is invalid. Why is this happening, can anyone explain, please ?
Macros and enums are separate things. Most importantly, a macro only exists at compile time so the preprocessor will replace all instances of MSD in the following code with 7 exactly as if you'd done a find-and-replace in your editor. Enums, on the other hand, exist at runtime and are generally numeric values mapped to symbols.
Now, with your code as you have it the MSD in your printf("%d\n", MSD); is replaced with 7 at compile time so the enum is never actually used. If you remove the 5th line of code the compiler sees an empty enum because the #define MSD 7 macro is filtered out by the preprocessor leaving nothing else inside the enum.
If intention is to define a enum. we can define as below.
(we can define MSD in form of enum of a #define, either one of this is required to use "MSD" in code for value 7)
#include <stdio.h>
enum month {
MSD = 7,
TST = 1 // added just for ref
};
// in linux requires int main() { <code> return 0;}
void main() {
printf("enum MSD == %d\n", MSD);
}
I was reading a source code of header file and wondered why have they written macros that way, in which I have posted
I think you may have misread a header file that was doing this slightly different thing:
enum thing_enum {
THING_ONE = 1,
#define THING_ONE THING_ONE
THING_TWO,
#define THING_TWO THING_TWO
// etc
};
This is the same as writing a normal enum declaration
enum thing_enum {
THING_ONE = 1,
THING_TWO,
// etc
};
and then, also, defining each enumerator as a macro that expands to itself:
#define THING_ONE THING_ONE
#define THING_TWO THING_TWO
// etc
Written this way, it should be clearer why you get an error when you comment out the ‘MSD’ line in your code: the #define doesn’t contribute anything to the definition of the enum, so you have an enum with no values, which the language does not allow.
Header files do this odd-looking thing because it makes each THING_ constant be both a macro and an enum value, which means you can use all the features of enum to set their values (e.g. in my example THING_TWO is equal to 2 without my having had to say so explicitly) and the names will be made visible to the debugger, but it’s still possible to check for the existence of a particular constant with #ifdef.
The disadvantages are that it doubles the length of the definition of the set of constants, you cannot make the type of each constant be anything other than int, and the constants cannot be used in an #if expression (except as the argument of defined).
(Note: A macro that expands to itself does not put the preprocessor into an infinite loop. THING_ONE is replaced with THING_ONE once and then the preprocessor moves on to the next token.)
MSD has nothing do with declaring above #define MSD 7, the reason for error is that enum{ }; should not be empty.
you get the below error if enum is empty.
main.c:12:1: error: empty enum is invalid
};
Try declaring another enum value there instead of MSD, it will work as shown below.
#defines are text replacements, they dont need any declarations, just definitions.
#include <stdio.h>
enum month {
x = 0
//MSD //If I remove or comment this variable declaration, code does not work, why?
#define MSD 7
};
void main() {
printf("%d\n", MSD);
}

Macros expansion using ## operator

Hi every one the problem is that i have in this macro
#define ADD_COMP(s1,s2,type)({\
int _x=0;\
for(int i=0;i<n_addrs;i++){\
if(memcmp(s1,&(s2->##type),6)!=0){\
_x=-1;\
}else{\
break;\
}\
}\
_x;\
})
s1 is a simple array and s2 is a structure with 4 vectors as members like this
typedef struct example{
char[6] one,
char[6] two,
char[6] three
}example;
Now for own reason i need to create a function that compares the s1 array of size 6 bytes with only a member of example, so for this purpose i wrote ADD_CMP using ## operator to be more generic as possible
So i defined:
#define one
#define two
#define three
and i used the function different times in this way hoping in the succes of macros expansion
ADD_COMP(some_array,example1,one)
ADD_COMP(some_array,example1,two)
ADD_COMP(some_array,example1,three)
but the compiler return as error:
error: pasting "->" and "one" does not give a valid preprocessing token
error: pasting "->" and "two" does not give a valid preprocessing token
error: pasting "->" and "three" does not give a valid preprocessing token
How can i fix it without write the same function for every structure member?
As the error suggests, there never was need for ##, as it is used to paste two preprocessing tokens to form a single one.
#define VAR(name, num) name##num
int VAR(foo, 1); // foo and 1 must be pasted together as foo1, instead of foo 1
The macro should compile with fixes to several syntax errors and missing declarations
#include<stdlib.h>
#include<string.h>
int n_addrs = 6;
#define ADD_COMP(s1,s2,type) {\
int _x=0;\
for(int i=0;i<n_addrs;i++){\
if(memcmp(s1,&(s2->type),6)!=0){\
_x=-1;\
}else{\
break;\
}\
}\
_x;\
}
typedef struct example{
char one[6];
char two[6];
char three[6];
}example;
void foo(void)
{
example* example1 = malloc(sizeof(example));
char some_array[6];
ADD_COMP(some_array,example1,one)
ADD_COMP(some_array,example1,two)
ADD_COMP(some_array,example1,three)
}
Note a compound statement { ... } isn't an expression and can not be used as such. By adding extra parentheses around it, you are using gnu's extension and is not standard C.
You should instead, just write a function to do this instead. You will then be able to return _x and with modern optimizers, there should be negligible to non-existant overhead.
The token pasting operator is designed for cases where you want to glue two different preprocessor tokens into a single token. For example, you might write something like
#define Glue(x) x my##x_
and then write
Glue(int);
to get this variable declaration:
int my_int;
Here, token-pasting combined the token “my_” with the token “int” to form the new token “my_int,” a new single token representing a name.
Once you paste two tokens together, the preprocessor doesn’t rescan them to figure out whether it’s a compound of several different individual tokens. It treats whatever is formed as a single token. For example, this code won’t compile:
#define BadAdd(x, y) x##+##y
int z = BadAdd(137, 42);
The issue here is that the token pasting forms a single preprocessing token 137+42. The preprocessor then tries to map this preprocessing token to a single logical token, but there’s no single token that this could correspond to. Normally, C or C++ would treat this as three separate tokens (137, +, and 42), but since you’ve forcibly glued them together the compiler has no idea what it’s looking at.
Contrast this with a more traditional Add macro, which for the purposes of exposition omits tons of important parentheses:
#define Add(x, y) x + y
int z = Add(137, 42);
Here, Add(137, 42) expands out to a sequence of three tokens (137, +, 42), which the compiler in a later phase can then interpret as an addition expression.
The macro you wrote above is like the BadAdd macro. By gluing the -> token together with a field name, you end up with a single unit like ->one that the compiler can’t meaningfully interpret as a single token. Just delete the ## here - just like going from BadAdd to Add, this will generate a sequence of tokens rather than a single token, which is what you want here.
I am not sure why you are attempting to use ##pre-processor token.
The macro can simply be:
#define ADD_COMP(s1, s2, member) ({\
int _x = 0;\
for (int i = 0; i < n_addrs; i++){\
if(memcmp(s1, &(s2.member), 6) !=0 ){\
_x = -1;\
} else {\
break;\
}\
}\
_x;\
})
and be used as:
ADD_COMP(some_array,example1,one);
ADD_COMP(some_array,example1,two);
ADD_COMP(some_array,example1,three);
More importantly, the macro looks easy enough that it can probably be replaced with a function, which is always a better option. I am not able to suggest how to transform the macro to a function since it's not clear to me where n_addrs comes from and where and how _x is used.

incomprehensible C macro

I bumped into the following macro while analyzing a code.
#define __COMMAND_HANDLER(name, extra ...) int name(struct command_invocation *cmd, ## extra)
The function name is passed as an argument to __COMMAND_HANDLER however there is no definition of this function anywhere else in the code. The cmd argument's type (command_invocation) is defined. Basically I couldn't understand the functionality of this macro because I couldn't find the definition of the function name. Is name some kind of pre-defined function in standard C library ? Does this macro definition make sense if name is not defined ?
Durning preprocession, the preprocessor will replace all occurrences of __COMMAND_HANDLER(name, extra ...) macro to its body with replacing each occurences of name and extra... inside its body to the tokens you specified.
This means in this case that whatever you enter for name argument, it will be a function name, and extra... will be its additional parameters beside the first one (struct command_invocation *cmd).
For example the following line:
__COMMAND_HANDLER(foo, int param) {
/* definition */
}
after preprocessing will be:
int foo(struct command_invocation *cmd, int param) {
/* definition */
}
One important thing has to be clarified: the ## before extra and named variable argument (using extra... instead of ...) are not the part of the c standard but they are GNU extensions. The effect of ## after comma lets you specify nothing for variable argument. Compiling your example with GCC (with -pedantic flag) when it's used as follows, you will see warning messages:
/* The following example will print the following messages:
* warning: ISO C does not permit named variadic macros [-Wvariadic-macros]
* warning: ISO C99 requires at least one argument for the "..." in a variadic
* macro
*/
__COMMAND_HANDLER(bar);
Normally the ## is the operator for token concatenation, i.e. two tokens on either side of a ## operator are combined into a single one. For example:
#include <stdio.h>
#define FOO(name, number) void name##number()
FOO(bar, 1) { puts("I'm first."); }
FOO(bar, 2) { puts("I'm second."); }
int main() {
bar1();
bar2();
return 0;
}
This is a macro and name is a parameter.
You use it like this:
__COMMAND_HANDLER(hello, char* world)
During pre-process stage, it would transform your code into:
int hello(struct command_invocation *cmd, char *world);
In this case, name is passed as hello, and extra = char* world.
If you don't pass anything for extra, ## will discard the comma.
In short: the macro is creating the function with the name specified by the parameter name and optional additional arguments specified by extra ....
Note: names starting with a double underscore is implementation reserved and shouldn't be used.
The macro is variadic.
The second argument to the macro extra ... provides a name to use instead of the default __VA_ARGS__ inside the function declaration macro. This is a GNU extension
## extra is another GNU extension that specifies to the preprocessor that if the second argument to the macro __COMMAND_HANDLER is omitted, the preceding comma can be removed and the function called without it.
The reason you can't find the declaration of name is because it's a parameter to your macro! The macro itself is declaring a new function with whatever is in name, and the arguments provided, with the default first argument of struct command_invocation *cmd.
Here are some examples:
Calling:
__COMMAND_HANDLER(cmd,char * w)
Would result in the function declaration of:
int cmd(struct command_invocation *cmd,char * w)
Whereas calling:
__COMMAND_HANDLER(cmd2)
would result in the function declaration of:
int cmd2(struct command_invocation *cmd)

How to pass a macro's result to another macro?

I have two macros in my C code the helps me to compose the name of certain variables. As an example, consider the following:
#define MACROA(name) A_##name
#define MACROB(name) B_##name
void *MACROB(MACROA(object));
So, I'm trying to declare a variable called B_A_object. However, this doesn't work and the compiler throws me the message:
object.c:27:21: error: a parameter list without types is only allowed in a function definition
void *MACROB(MACROA(object));
^
object.c:26:26: note: expanded from macro 'MACROB'
#define MACROB(name) B_##name
^
So, it seems the preprocessor is not taking the result of MACROA(object), but it is considering the expression itself so that it tries to make B_MACROA(object). So, what do I have to do to make the preprocessor consider the result of a macro passed to another macro?
The concatenation operator acts weird. It concatenates first and evaluates later:
void *MACROB(MACROA(object)); // The original line
void *B_MACROA(object); // Becomes this, nothing more to expand
You can solve it this way:
#define CONC(a,b) a ## b
#define MACROA(name) CONC(A_, name)
#define MACROB(name) CONC(B_, name)

Resources