Wie genau funktioniert der Double-Stringize-Trick?

82

Mit mindestens einigen C- Präprozessoren können Sie den Wert eines Makros anstelle seines Namens stringisieren, indem Sie es über ein funktionsähnliches Makro an ein anderes übergeben, das es stringiert:

#define STR1(x) #x
#define STR2(x) STR1(x)
#define THE_ANSWER 42
#define THE_ANSWER_STR STR2(THE_ANSWER) /* "42" */

Beispielanwendungsfälle hier .

Dies funktioniert zumindest in GCC und Clang (beide mit -std=c99), aber ich bin mir nicht sicher, wie es in C-Standard-Begriffen funktioniert.

Ist dieses Verhalten durch C99 garantiert?
Wenn ja, wie garantiert C99 dies?
Wenn nicht, ab wann wechselt das Verhalten von C-definiert zu GCC-definiert?

Peter Hosey
quelle
1
Wenn Sie "mindestens einige" sagen, bedeutet das, dass Sie eine gesehen haben, bei der es nicht funktioniert? Ich bin bereit, dem Anbieter einen Fehlerbericht zu schreiben.
Jens
@Jens: Nein; Ich habe nicht. Jeder von mir verwendete Compiler (nämlich GCC und Clang) implementiert dieses Verhalten.
Peter Hosey

Antworten:

78

Ja, das ist garantiert.

Dies funktioniert, weil Argumente für Makros selbst makroerweitert sind, außer wenn der Name des Makroarguments im Makrotext mit dem Stringifier # oder dem Token-Paster ## angezeigt wird.

6.10.3.1/1:

... Nachdem die Argumente für den Aufruf eines funktionsähnlichen Makros identifiziert wurden, erfolgt die Argumentersetzung. Ein Parameter in der Ersetzungsliste wird durch das entsprechende Argument ersetzt, sofern nicht darin ein # oder ## Vorverarbeitungstoken oder ein ## Vorverarbeitungstoken (siehe unten) steht, nachdem alle darin enthaltenen Makros erweitert wurden ...

Wenn Sie dies tun, erhalten STR1(THE_ANSWER)Sie "THE_ANSWER", da das Argument von STR1 nicht durch Makros erweitert ist. Das Argument von STR2 wird jedoch makroerweitert, wenn es in die Definition von STR2 eingesetzt wird, wodurch STR1 ein Argument von 42mit dem Ergebnis "42" erhält .

Steve Jessop
quelle
21

Als Steve Notizen wird diese guarenteed, und es hat sich seit dem C89 - Standard guarenteed worden - , dass der Standard der kodifizierten die war # und ## Operatoren in Makros und Mandate rekursiv Makros in args erweitern , bevor sie in den Körper , wenn und nur ersetzen , wenn Der Body wendet kein # oder ## auf das Argument an. C99 ist in dieser Hinsicht unverändert gegenüber C89.

Chris Dodd
quelle
+1, wenn Sie sich die Zeit genommen haben, um zu bestätigen, dass es auch Teil von C89 ist. Einige von uns kümmern sich um die Portabilität, einschließlich der Erstellung von Code, den Benutzer, die im C89-Modus kompilieren, verwenden können. Noch vor wenigen Jahren war gcc-Versionen standardmäßig auf C89 eingestellt (plus gcc-Erweiterungen, um fair zu sein). MSVC unterstützt zuletzt nur C89 und ist eingebettet oder Legacy-Systeme haben manchmal auch nur C89-Compiler. C89 bietet eine hervorragende Portabilität im "Erdgeschoss", einem Standard mit dem geringsten gemeinsamen Nenner, auf den sich die Benutzer konzentrieren können, um alles zu kompilieren und auszuführen, was heute in der Praxis verwendet wird. Es ist also sehr schön zu sehen, dass es in Erinnerung bleibt.
mtraceur