# und ## in Makros

Lesezeit: 2 Minuten

Benutzeravatar von algo-geeks
Algo-Geeks

  #include <stdio.h>
  #define f(a,b) a##b
  #define g(a)   #a
  #define h(a) g(a)

  int main()
  {
    printf("%s\n",h(f(1,2)));
    printf("%s\n",g(f(1,2)));
    return 0;
  }

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?

Benutzeravatar von Christoffer
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").

Benutzeravatar von smwikipedia
smwikipedia

Im Folgenden finden Sie einige verwandte Konzepte zu Ihrer Frage:

Argument-Vorscan:

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.

Stringifizierung

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.

Token-Einfügen / Token-Verkettung:

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.

1409050cookie-check# und ## in Makros

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy