Создание макроса C С ## и LINE (конкатенация токенов с макросом позиционирования)

Я хочу создать макрос C, который создает функцию с именем на основе на номер строки. Я думал, что могу сделать что-то вроде (реальная функция будет иметь операторы в фигурных скобках):

#define UNIQUE static void Unique_##__LINE__(void) {}

который я надеялся расширить до чего-то вроде:

static void Unique_23(void) {}

Это не сработает. С конкатенацией токенов макросы позиционирования рассматриваются буквально, заканчивая расширением до:

static void Unique___LINE__(void) {}

возможно ли это сделать?

(Да, есть реальная причина, по которой я хочу сделать это, независимо от того, насколько бесполезным это кажется).

2 ответов


проблема в том, что когда у вас есть замена макроса, препроцессор будет рекурсивно расширять макросы только в том случае, если ни строковый оператор # ни оператор вставки токена ## применяются к нему. Таким образом, вы должны использовать некоторые дополнительные слои косвенности, вы можете использовать оператор вставки токенов с рекурсивно расширенным аргументом:

#define TOKENPASTE(x, y) x ## y
#define TOKENPASTE2(x, y) TOKENPASTE(x, y)
#define UNIQUE static void TOKENPASTE2(Unique_, __LINE__)(void) {}

затем, __LINE__ расширяется до номера строки во время расширения UNIQUE (так как это не связано с либо # или ##), а затем вставка токена происходит во время расширения TOKENPASTE.

следует также отметить, что существует также __COUNTER__ макрос, который расширяется до нового целого числа каждый раз, когда он оценивается, в случае, если вам нужно иметь несколько экземпляров UNIQUE макрос на той же строке. Примечание:__COUNTER__ поддерживается MS Visual Studio, GCC (начиная с V4.3), и лязг, но не является стандартным C.


GCC не требует " обертывания "(или реализации), если результат не должен быть"stringified". Gcc имеет функции, но все можно сделать с простой версией C 1 (и некоторые утверждают, что Berkeley 4.3 C настолько быстрее, что стоит научиться использовать).

**Clang (llvm) не делает пробел правильно для расширения макроса-он добавляет пробелы (которые, безусловно, уничтожают результат как идентификатор C для дальнейшей предварительной обработки) **, clang просто не делает # или * расширение макроса как C Ожидается, что препроцессор будет десятилетиями. Основным примером является компиляция X11, макрос "Concat3" сломан, его результат теперь называется неправильным идентификатором C, который, конечно, не удается построить. и я начинаю понимать, что неудачи в строительстве-это их профессия.

Я думаю, что ответ здесь "новый C, который нарушает стандарты, плохой C", эти хаки всегда выбирают (clobber пространства имен), они меняют значения по умолчанию без причины, но на самом деле не "улучшают C" (за исключением их собственных говорят так: что я говорю, это хитрость сделано, чтобы объяснить, почему они уходят со всеми поломки никто еще не сделал их ответственными за).


Это не проблема, что более ранние предварительные процессоры C не поддерживали UNIq_ ()_ _ потому что они поддерживали #pragma, которая позволяет "хакерство бренда компилятора в коде помечаться как хакерство" , а также функционировать так же хорошо, не влияя на стандарты: так же, как изменение значений по умолчанию бесполезно wonton breakage, и так же, как изменение функции при использовании того же имя (пространство имен clobbering)... вредоносное ПО на мой взгляд