Wenn man sich nur das Programm ansieht, “könnte” man erwarten, dass die Ausgabe für beide printf-Anweisungen gleich ist. Aber beim Ausführen des Programms erhalten Sie es als:
bash$ ./a.out
12
f(1,2)
bash$
Wieso ist es so?
Christoffer
Denn so funktioniert der Präprozessor.
Ein einzelnes „#“ erstellt eine Zeichenfolge aus dem angegebenen Argument, unabhängig davon, was dieses Argument enthält, während das doppelte „##“ ein neues Token erstellt, indem die Argumente verkettet werden.
Versuchen Sie, sich die vorverarbeitete Ausgabe anzusehen (z. B. mit gcc -E), wenn Sie besser verstehen möchten, wie die Makros ausgewertet werden.
Ich denke, die Frage ist eher, wie h(f(1,2)) und g(f(1,2)) abweichen. In diesem Sinne ist die Antwort von @joe-bloggs klarer.
– Wsewolod Ganin
18. Mai 2019 um 17:34 Uhr
Hallo, was wäre wenn #define STR "AAA "#define f(a) (STR#a) Wille f(BBB) sein "AAA ""BBB" oder "AAA BBB"? Kann diese Single # in der Mitte von Strings Argumente verketten?
– leoleohu
13. Mai 2021 um 7:58 Uhr
Ein Vorkommen eines Parameters in einem funktionsähnlichen Makro, es sei denn, es ist der Operand von # oder ##, wird erweitert, bevor es ersetzt und das Ganze für eine weitere Erweiterung erneut gescannt wird. Da g‘s Parameter ist der Operand von #wird das Argument nicht erweitert, sondern sofort gestringt ("f(1,2)"). Da h‘s Parameter ist nicht der Operand von # Noch ##wird das Argument zuerst erweitert (12), dann ersetzt (g(12)), dann erfolgt ein erneutes Scannen und eine weitere Erweiterung ("12").
smwikipedia
Im Folgenden finden Sie einige verwandte Konzepte zu Ihrer Frage:
Makroargumente sind vollständig makroerweitert Vor Sie werden in einen Makrokörper eingesetzt, sofern dies nicht der Fall ist besaitet oder eingefügt
mit anderen Token. Nach der Substitution wird der gesamte Makrokörper einschließlich der ersetzten Argumente gescannt wieder für zu erweiternde Makros. Das Ergebnis ist, dass die Argumente zweimal gescannt werden, um darin enthaltene Makroaufrufe zu erweitern.
Wenn ein Makroparameter mit einem führenden ‘#’ verwendet wird, ersetzt der Präprozessor ihn durch den wörtlichen Text des tatsächlichen Arguments, konvertiert in a String-Konstante.
#ABC => "ABC" <---- Beachten Sie das einschließende doppelte Anführungszeichen, das durch den Stringifizierungsprozess hinzugefügt wird.
Es ist oft nützlich, beim Erweitern von Makros zwei Token zu einem zusammenzuführen. Das nennt man Token einfügen oder Token-Verkettung. Der Vorverarbeitungsoperator „##“ führt das Einfügen von Token durch. Wenn ein Makro erweitert wird, werden die beiden Token auf beiden Seiten jedes ‘##’-Operators zu einem einzigen Token kombiniert, das dann das ‘##’ und die beiden ursprünglichen Token in der Makroerweiterung ersetzt.
Der detaillierte Prozess Ihres Szenarios sieht also folgendermaßen aus:
h(f(1,2))
-> h(12) // f(1,2) pre-expanded since there's no # or ## in macro h
-> g(12) // h expanded to g
"12" // g expanded as Stringification
g(f(1,2))
-> "f(1,2)" //f(1,2) is literally strigified because of the `#` in macro g. f(1,2) is NOT expanded at all.