Ich möchte ein C-Makro erstellen, das eine Funktion mit einem Namen basierend auf der Zeilennummer erstellt. Ich dachte, ich könnte so etwas tun (die eigentliche Funktion hätte Aussagen in geschweiften Klammern):
#define UNIQUE static void Unique_##__LINE__(void) {}
Was ich hoffte, würde sich auf so etwas wie Folgendes ausweiten:
static void Unique_23(void) {}
Das geht nicht Bei der Token-Verkettung werden die Positionierungsmakros buchstäblich behandelt und schließlich erweitert auf:
static void Unique___LINE__(void) {}
Ist das möglich?
(Ja, es gibt einen wirklichen Grund, warum ich das tun möchte, egal wie nutzlos dies scheint).
c
macros
concatenation
token
DD.
quelle
quelle
__LINE__
(obwohl dies ein häufiger Anwendungsfall ist.Antworten:
Das Problem ist, dass der Präprozessor bei einer Makroersetzung die Makros nur dann rekursiv erweitert, wenn weder der Stringisierungsoperator
#
noch der Token- Einfügeoperator darauf##
angewendet werden. Wenn Sie also einige zusätzliche Indirektionsebenen verwenden müssen, können Sie den Token-Pasting-Operator mit einem rekursiv erweiterten Argument verwenden:Wird
__LINE__
dann während der Erweiterung von auf die Zeilennummer erweitertUNIQUE
(da es nicht an entweder#
oder beteiligt ist##
), und dann erfolgt das Einfügen des Tokens während der Erweiterung vonTOKENPASTE
.Es sollte auch beachtet werden, dass es auch das
__COUNTER__
Makro gibt, das bei jeder Auswertung auf eine neue Ganzzahl erweitert wird, falls Sie mehrere Instanziierungen desUNIQUE
Makros in derselben Zeile benötigen . Hinweis:__COUNTER__
Wird von MS Visual Studio, GCC (seit V4.3) und Clang unterstützt, ist jedoch nicht Standard C.quelle
__COUNTER__
Makro hat bei mir in gcc nicht funktioniert; obwohl der__LINE__
wie angekündigt funktioniert hat.GCC erfordert kein "Wrapping" (oder Realisieren), es sei denn, das Ergebnis muss "stringifiziert" werden. Gcc hat Funktionen, aber ALLES kann mit C-Version 1 durchgeführt werden (und einige behaupten, Berkeley 4.3 C sei so viel schneller, dass es sich lohnt, die Verwendung zu lernen).
** Clang (llvm) MACHT WEISSEN RAUM NICHT RICHTIG für die Makroerweiterung - es fügt Leerzeichen hinzu (was sicherlich das Ergebnis als C-Kennung für die weitere Vorverarbeitung zerstört) **, Clang führt einfach keine # oder * Makroerweiterung durch als C-Präprozessor wird für Jahrzehnte erwartet. Das beste Beispiel ist das Kompilieren von X11, das Makro "Concat3" ist kaputt, das Ergebnis ist jetzt MISNAMED C Identifier, das natürlich nicht erstellt werden kann. und ich fange an, Dinge zu bauen, die scheitern, sind ihr Beruf.
Ich denke, die Antwort hier ist "Neues C, das gegen Standards verstößt, ist schlechtes C". Diese Hacks entscheiden sich immer dafür (Clobber-Namespaces), die Standardeinstellungen ohne Grund zu ändern, aber C nicht wirklich "zu verbessern" (außer nach eigenem Ermessen: was ich Sagen wir, es wurde eine Erfindung gemacht, um zu erklären, warum sie mit all dem Bruch davonkommen, für den sie noch niemand verantwortlich gemacht hat.
Es ist kein Problem, dass die früheren C-Vorprozessoren UNIq_ () __ nicht unterstützten, da sie #pragma unterstützten, wodurch "Hacker-Compiler-Marken im Code als Hackery gekennzeichnet werden können" und ebenso gut funktionieren, OHNE Standards zu beeinflussen: genauso wie Änderungen Standardeinstellungen sind nutzlose Wonton-Brüche, und genauso wie das Ändern der Funktionsweise einer Funktion unter Verwendung des gleichen Namens (Namespace-Clobbering) meiner Meinung nach ... Malware ist
quelle