[英]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. gcc filename.c -E 显示没有进行替换。 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
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.当谈到标识符时, _CLASS
是一个标记,而_CLASS_Pool
完全是另一个标记,因为它们是不同的标识符。 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.不,它会在识别标识符之前吞噬所有_CLASS_Pool
。
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.因此,您需要的是一种机制,通过该机制预处理器接受_CLASS
作为令牌,将其扩展,然后将其粘贴到另一个令牌。 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.第一个CONCAT
接受您的参数,并将它们转发给另一个函数,如宏。 Forwarding them allows for any intermediate expansion, like _CLASS -> Object
.转发它们允许任何中间扩展,比如_CLASS -> Object
。 Tokens that aren't object-like macros remains unchanged.不是类对象宏的标记保持不变。 CONCAT_
then simply applies the in-built token pasting operator. CONCAT_
然后简单地应用内置的令牌粘贴操作符。 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 ( _[AZ][0-9a-zA-Z]*
), to the implementation, for any use.顺便说一句,C 标准将所有以下划线开头、后跟大写字母 ( _[AZ][0-9a-zA-Z]*
) 的标识符保留给实现,以供任何使用。 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.通常,尽量避免在标识符中使用下划线开头,除非您牢记所有保留标识符的规则。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.