用 C 宏替换 function/variable 名称的一部分
Replace part of a function/variable name with C macros
我正在编写一些我想多次使用的代码,但函数名和变量名略有不同。我想用宏替换部分函数和变量名。 gcc filename.c -E 表明没有进行替换。我该如何纠正?
这是替换前文件中的一些代码:
#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
预处理器对令牌进行操作。当涉及到标识符时,_CLASS
是一个标记,而 _CLASS_Pool
则完全是另一个标记,因为它们是不同的标识符。预处理器不会在解析标识符的过程中停下来检查它的一部分是否是另一个标识符。不,在识别标识符是什么之前,它会吞噬所有 _CLASS_Pool
。
如果您听说过预处理器进行纯文本替换,那是一种严重的过度简化。它在 代币 上运行,最好始终牢记这一点。
所以你需要的是一种机制,预处理器通过这种机制接受 _CLASS
作为标记,扩展它,然后将它粘贴到另一个标记。幸运的是,这些机制已经存在。可以这样写:
#define CONCAT(a, b) CONCAT_(a, b)
#define CONCAT_(a, b) a ## b
这样使用:
_CLASS* CONCAT(_CLASS, _Pool)[POOLLEVEL1] = { 0 };
int CONCAT(_CLASS, _Available_Head) = -1;
/* and so forth */
第一个 CONCAT
接受您的参数,并将它们转发给另一个函数,如宏。转发它们允许任何中间扩展,如 _CLASS -> Object
。不是类对象宏的标记保持不变。 CONCAT_
然后简单地应用内置的令牌粘贴运算符。您可以检查结果并进一步调整它。
顺便说一句,C 标准将所有以下划线开头,后跟大写字母 (_[A-Z][0-9a-zA-Z]*
) 的标识符保留给实现,以供任何使用。自己使用它们会使您对未定义的行为敞开大门。通常,尽量避免在标识符中使用前导下划线,除非您熟记保留标识符的所有规则。
我正在编写一些我想多次使用的代码,但函数名和变量名略有不同。我想用宏替换部分函数和变量名。 gcc filename.c -E 表明没有进行替换。我该如何纠正?
这是替换前文件中的一些代码:
#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
预处理器对令牌进行操作。当涉及到标识符时,_CLASS
是一个标记,而 _CLASS_Pool
则完全是另一个标记,因为它们是不同的标识符。预处理器不会在解析标识符的过程中停下来检查它的一部分是否是另一个标识符。不,在识别标识符是什么之前,它会吞噬所有 _CLASS_Pool
。
如果您听说过预处理器进行纯文本替换,那是一种严重的过度简化。它在 代币 上运行,最好始终牢记这一点。
所以你需要的是一种机制,预处理器通过这种机制接受 _CLASS
作为标记,扩展它,然后将它粘贴到另一个标记。幸运的是,这些机制已经存在。可以这样写:
#define CONCAT(a, b) CONCAT_(a, b)
#define CONCAT_(a, b) a ## b
这样使用:
_CLASS* CONCAT(_CLASS, _Pool)[POOLLEVEL1] = { 0 };
int CONCAT(_CLASS, _Available_Head) = -1;
/* and so forth */
第一个 CONCAT
接受您的参数,并将它们转发给另一个函数,如宏。转发它们允许任何中间扩展,如 _CLASS -> Object
。不是类对象宏的标记保持不变。 CONCAT_
然后简单地应用内置的令牌粘贴运算符。您可以检查结果并进一步调整它。
顺便说一句,C 标准将所有以下划线开头,后跟大写字母 (_[A-Z][0-9a-zA-Z]*
) 的标识符保留给实现,以供任何使用。自己使用它们会使您对未定义的行为敞开大门。通常,尽量避免在标识符中使用前导下划线,除非您熟记保留标识符的所有规则。