I am writing some code that I will want to use multiple times with slightly different function and variable names. I want to replace part of the function and variable names with a macro. gcc filename.c -E shows that the substitution is not being made. How do I rectify this?
Here is some code from the file, before substitution:
#define _CLASS Object
#define POOLLEVEL1 1024
#define POOLLEVEL2 1024
typedef struct {
int Self;
int Prev;
int Next;
int In_Use;
//----data----//
//----function pointers----//
} Object;
_CLASS* _CLASS_Pool[POOLLEVEL1] = { 0 };
//Note on POOLLEVEL1, POOLLEVEL2: _CLASS_Pool[] is an array of pointers to arrays of type _CLASS. The number of objects in these arrays is LEVEL2, the maximum number of arrays of type object is LEVEL1; The arrays of type object are allocated when needed.
int _CLASS_Available_Head = -1;
int _CLASS_Available_Tail = -1;
//Start and finish of list of available objects in pool.
// More follows
Macro substitution is a mechanism that provides a string substitution. It can be achieved through "#deifne". It is used to replace the first part with the second part of the macro definition, before the execution of the program. The first object may be a function type or an object.
The C standard mandates that the only place the identifier __VA_ARGS__ can appear is in the replacement list of a variadic macro. It may not be used as a macro name, macro argument name, or within a different type of macro. It may also be forbidden in open text; the standard is ambiguous.
If you accidentally redefine a name with a #define , the compiler silently changes the meaning of your program. With const or enum you get an error message.
You can't. Macros are expanded by the Preprocessor, which happens even before the code is compiled. It is a purely textual replacement. If you need to change something at runtime, just replace your macro with a real function call.
The preprocessor operates on tokens. And when it comes to identifiers _CLASS
is one token, while _CLASS_Pool
is another entirely, since they are different identifiers. The preprocessor is not going to stop in the middle of parsing an identifier to check if part of it is another identifier. No, it will gobble up all of _CLASS_Pool
before recognizing what the identifier is.
If you ever heard the preprocessor does pure textual substitution, that was a gross over-simplification. It operates on tokens, something best to always keep in mind.
So what you need is a mechanism by which the preprocessor accepts _CLASS
as a token, expands it, and then pastes it to another token. Fortunately for you, those mechanisms already exist. It can be written as follows:
#define CONCAT(a, b) CONCAT_(a, b)
#define CONCAT_(a, b) a ## b
To be used like this:
_CLASS* CONCAT(_CLASS, _Pool)[POOLLEVEL1] = { 0 };
int CONCAT(_CLASS, _Available_Head) = -1;
/* and so forth */
The first CONCAT
accepts your arguments, and forwards them to another function like macro. Forwarding them allows for any intermediate expansion, like _CLASS -> Object
. Tokens that aren't object-like macros remains unchanged. CONCAT_
then simply applies the in-built token pasting operator. You can examine the result and tweak it further.
As an aside, the C standard reserves all identifiers that begin by an underscore, followed by an uppercase letter (_[A-Z][0-9a-zA-Z]*
), to the implementation, for any use. Using them yourself leaves you open for undefined behavior. In general, try to avoid leading underscore in identifiers, unless you know all the rules for reserved identifiers by heart.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With