Створення макросу C за допомогою ## та __LINE__ (об'єднання лексеми з макросом позиціонування)


107

Я хочу створити макрос C, який створює функцію з іменем на основі номера рядка. Я думав, що я можу зробити щось на кшталт (реальна функція матиме заяви в дужках):

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

Я сподівався розширитись на щось на кшталт:

static void Unique_23(void) {}

Це не працює. За допомогою конкатенації лексеми макроси позиціонування обробляються буквально, закінчуючись розширенням до:

static void Unique___LINE__(void) {}

Чи можливо це зробити?

(Так, є реальна причина, що я хочу зробити це незалежно від того, наскільки це марно не здається).


Я думаю, ви можете змусити це працювати з непрямим розширенням макросу .
Бен Стігліц

4
можливий дублікат Як з'єднати двічі з препроцесором C і розгорнути макрос, як у "arg ## _ ## MACRO"? Те саме стосується будь-якого макросу, окрім цього __LINE__(хоча це звичайний випадок використання.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Відповіді:


176

Проблема полягає в тому, що коли у вас заміна макросів, препроцесор розширюватиме макроси рекурсивно лише у тому випадку, якщо до нього #не застосовані ні оператор стругування, ні оператор вставки лексеми ##. Отже, вам доведеться використовувати додаткові шари непрямості, ви можете використовувати оператор вставки лексеми з рекурсивно розширеним аргументом:

#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) та Clang, але не є стандартом C.


3
Я боюся, що це не працює з GNU cpp. TOKENPASTE використовує LINE як буквальний. TOKENPASTE (Unique_, LINE ) розширюється до Unique___LINE__
DD.

3
@DD: D'oh, виправлено зараз. Потрібно 2 шари непрямості, а не 1.
Адам Розенфілд

__COUNTER__Макрос не працює для мене в ПКУ; хоча той __LINE__працював так, як рекламували.
Тайлер

2
Трохи додаткової інформації для тих, хто намагається COUNTER , згідно з msdn.microsoft.com/en-us/library/b0084kay(v=vs.80).aspx - це макрос, специфічний для Microsoft.
Ельва

3
Будь-яке пояснення, чому вам потрібен 2 рівень непрямості? Я спробував це лише з одним, відсутнім # і ##, і це не розширює його на VS2017. Мабуть, те саме стосується і GCC. Але якщо додати 2-й рівень непрямості, то він дійсно розшириться. Магія?
Гейб Халсмер

-2

GCC не вимагає "обгортання" (або реалізації), якщо результат не потрібно "пошаровувати". У Gcc є функції, але ВСЕ можна зробити за допомогою простої версії C 1 (а деякі аргументують Берклі 4.3 С набагато швидше, варто навчитися користуватися).

** Clang (llvm) НЕ ПРАВИЛЬНО БІЛИЙ ПРОСТІР для розширення макросу - він додає пробіл (який, безумовно, знищує результат як ідентифікатор C для подальшої попередньої обробки) **, clang просто не робить # або * розширення макросу як передпроцесор С, як очікується, протягом десятиліть. Прекрасним прикладом є компіляція X11, макрос "Concat3" порушений, тепер це результат MISNAMED C Ідентифікатор C, який, звичайно, не вдається створити. і я починаю робити речі невдало - це їх професія.

Я думаю, що відповідь тут - "новий C, який порушує стандарти, поганий C", ці хаки завжди обирають (простори імен клобурів), вони змінюють типові настройки без причини, але насправді не "покращують C" (за винятком власних скажу так: що я Скажімо, контрацепція зроблена для пояснення того, чому вони розійдуться з усіма поломками, поки ніхто не притягує їх до відповідальності).


Це не проблема в тому, що попередні попередні процесори C не підтримували UNIq_ () __, оскільки вони підтримували #pragma, що дозволяє " хакерські знаки компілятора в коді позначати як хакерські", а також функціонують так само БЕЗ ефективних стандартів: так само, як змінюються Значення за замовчуванням - це марний злом Вантона, і так само зміна того, що функція виконує під час використання однойменної назви (простір імен, клобінг) - це, на мою думку, зловмисне програмне забезпечення

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.