Заменить часть имени функции / переменной макросами C - PullRequest
2 голосов
/ 16 апреля 2019

Я пишу некоторый код, который я хочу использовать несколько раз со слегка отличающимися именами функций и переменных. Я хочу заменить часть имен функций и переменных макросом. 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

1 Ответ

1 голос
/ 16 апреля 2019

Препроцессор работает с токенами. И когда дело доходит до идентификаторов _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]*), для реализации, для любого использования. Использование их самостоятельно оставляет вас открытыми для неопределенного поведения. В общем, старайтесь избегать начального подчеркивания в идентификаторах, если вы не знаете все правила для зарезервированных идентификаторов наизусть.

...