Tworzenie makra w języku C Z # # i linią (połączenie tokena z makrem pozycjonującym)

Chcę stworzyć makro C, które stworzy funkcję o nazwie opartej na numer linii. Myślałem, że mogę zrobić coś takiego (prawdziwa funkcja będzie miała wyrażenia w szelkach):

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

Które miałem nadzieję rozszerzyć na coś w rodzaju:

static void Unique_23(void) {}
To nie działa. Z tokenową konkatenacją, makra pozycjonujące są traktowane dosłownie, kończąc się na:
static void Unique___LINE__(void) {}
Czy to możliwe?

(tak, jest prawdziwy powód, dla którego chcę to zrobić nie matter how useless this seems).

Author: animuson, 2009-10-21

2 answers

Problem polega na tym, że w przypadku zastąpienia makra, preprocesor rozszerzy makra rekurencyjnie tylko wtedy, gdy ani operator stringizing #, ani operator wklejania tokenów ## nie zostaną do niego zastosowane. Tak więc, musisz użyć dodatkowych warstw indrection, możesz użyć operatora wklejania tokenów z rekurencyjnie rozszerzonym argumentem:

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

Następnie, {[3] } jest rozszerzany do numeru linii podczas rozszerzenia UNIQUE (ponieważ nie jest związany z # lub ##), następnie wklejanie tokenów następuje podczas rozszerzenia TOKENPASTE.

Należy również zauważyć, że istnieje również makro __COUNTER__, które rozszerza się do nowej liczby całkowitej za każdym razem, gdy jest ono obliczane, w przypadku gdy trzeba mieć wiele instancji makra UNIQUE w tej samej linii. Uwaga: {[8] } jest obsługiwany przez MS Visual Studio, GCC (od wersji 4.3) i Clang, ale nie jest standardem C.

 155
Author: Adam Rosenfield,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-10 16:55:52

GCC nie wymaga "owijania" (lub realizowania), chyba że wynik musi być "stringified". Gcc ma funkcje, ale wszystko można zrobić za pomocą zwykłego C w wersji 1 (a niektórzy twierdzą, że Berkeley 4.3 C jest o wiele szybszy, że warto nauczyć się go używać).

* * Clang (llvm) nie robi białych spacji poprawnie dla rozszerzenia makra - dodaje białe spacje (co z pewnością niszczy wynik jako identyfikator C do dalszego wstępnego przetwarzania)**, clang po prostu nie robi # lub * rozszerzenia makra jako C Preprocesora oczekuje się od dziesięcioleci. Najlepszym przykładem jest kompilacja X11, makro "Concat3" jest zepsute, jego wynik jest teraz błędnie nazwany identyfikatorem C, który oczywiście nie buduje. a ja zaczynam budować upadki to ich zawód.

Myślę, że odpowiedź tutaj jest "nowy C, który łamie standardy jest zły C", te hacki zawsze wybrać (clobber namespaces) zmieniają domyślne bez powodu, ale tak naprawdę nie " poprawić C "(z wyjątkiem ich własne powiedzieć tak: co mówię jest ustrojstwo wykonane aby wyjaśnić, dlaczego uciekają od wszystkich pęknięć, za które nikt jeszcze nie uczynił ich odpowiedzialnymi).


Nie jest problemem, że wcześniejsze procesory C nie wspierały UNIq_ ()__, ponieważ wspierały #pragma, które pozwala "hakerstwo marki kompilatora w kodzie być oznaczane jako hackery", a także funkcjonują równie dobrze bez wpływu na standardy: tak jak zmiana domyślnych wartości jest bezużyteczna wonton breakage, i tak samo zmiana tego, co funkcja robi przy użyciu tej samej nazwy (przestrzeń nazw clobbering) jest ... malware in my opinion

 -1
Author: nobodyisaliased,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-15 01:43:32