Я хочу создать макрос C, который создает функцию с именем на основе номера строки. Я подумал, что могу сделать что-то вроде (у реальной функции в фигурных скобках есть операторы):
#define UNIQUE static void Unique_##__LINE__(void) {}
Я надеялся, что это расширится до чего-то вроде:
static void Unique_23(void) {}
Это не работает. При конкатенации токенов макросы позиционирования обрабатываются буквально, в конечном итоге расширяясь до:
static void Unique___LINE__(void) {}
Возможно ли это сделать?
(Да, есть реальная причина, по которой я хочу это сделать, независимо от того, насколько это бесполезно).
__LINE__
(хотя это обычный вариант использования.Ответы:
Проблема в том, что когда у вас есть замена макроса, препроцессор будет рекурсивно разворачивать макросы только в том случае, если к нему не применяются ни строковый оператор,
#
ни оператор вставки токена##
. Итак, вам нужно использовать несколько дополнительных уровней косвенности, вы можете использовать оператор вставки токена с рекурсивно расширенным аргументом:Затем
__LINE__
расширяется до номера строки во время расширенияUNIQUE
(поскольку он не связан ни с одним,#
ни с##
), а затем вставка токена происходит во время расширенияTOKENPASTE
.Следует также отметить, что существует также
__COUNTER__
макрос, который расширяется до нового целого числа каждый раз при его оценке, на случай, если вам нужно иметь несколько экземпляровUNIQUE
макроса в одной строке. Примечание:__COUNTER__
поддерживается MS Visual Studio, GCC (начиная с V4.3) и Clang, но не является стандартом C.источник
__COUNTER__
Макрос не работает для меня в НКУ; хотя__LINE__
тот действительно работал, как рекламировалось.GCC не требует «обертывания» (или реализации), если результат не нужно «преобразовать в строку». Gcc имеет функции, но ВСЕ может быть выполнено с помощью простого C версии 1 (и некоторые утверждают, что Berkeley 4.3 C настолько быстрее, что стоит научиться использовать).
** Clang (llvm) НЕ ИСПОЛЬЗУЕТ БЕЛЫЙ ПРОБЕЛ ПРАВИЛЬНО для раскрытия макроса - он добавляет пробел (который, безусловно, уничтожает результат как идентификатор C для дальнейшей предварительной обработки) **, clang просто не выполняет # или * расширение макроса в качестве препроцессора C ожидается на протяжении десятилетий. Ярким примером является компиляция X11, макрос «Concat3» не работает, результатом является MISNAMED C Identifier, который, конечно, не может быть собран. и я начинаю понимать, что неудачи в сборке - их профессия.
Я думаю, что ответ здесь - «новый C, который нарушает стандарты, - это плохой C», эти хаки всегда предпочитают (стирать пространства имен), они меняют значения по умолчанию без причины, но на самом деле не «улучшают C» (за исключением их собственного, так сказать: который я скажем, это хитрое изобретение, чтобы объяснить, почему им сходит с рук все поломки, за которые никто еще не возложил на них ответственность).
Не проблема, что более ранние препроцессоры C не поддерживали UNIq_ () __, потому что они поддерживали #pragma, которая позволяет «пометить хакерство в коде компилятора как хакерство», а также работать так же БЕЗ влияния на стандарты: так же, как изменение defaults - это бесполезная поломка wonton, и точно так же, как изменение того, что функция делает при использовании того же имени (затирание пространства имен), на мой взгляд ... вредоносное ПО
источник