Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace part of a function/variable name with C macros

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
like image 921
BostonBrooks Avatar asked Apr 16 '19 06:04

BostonBrooks


People also ask

What is macro replacement in C?

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.

Where is __ Va_args __ defined?

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.

What to use instead of #define in C?

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.

Can we change macro value in C?

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.


1 Answers

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.

like image 71
StoryTeller - Unslander Monica Avatar answered Oct 18 '22 22:10

StoryTeller - Unslander Monica