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