Ich bin heute auf diese Syntax gestoßen und konnte nicht herausfinden, was sie bedeutet:
// Uses the GNU C statement expression extension
#define envSet(name) ({ \
static int initialised; \
static bool set; \
(void) "" name; \
if (!initialised || !g_cacheEnv) { \
const char *value = getenv(name); \
set = value != NULL; \
initialised = true; \
} \
set; \
})
Die spezifische Zeile, die ich nicht verstehe, lautet:
(void) "" name; \
Könnte jemand bitte etwas Licht ins Dunkel bringen?
Es sieht nach einer Möglichkeit aus, dies statisch sicherzustellen name
ist ein Zeichenfolgenliteral und kein anderer Typ.
Wenn Sie tun (void)"" "hello";
dann ist es ein gültiger C-Ausdruck.
Aber wenn Sie so etwas tun (void)"" 1;
dann bekommst du einen Syntaxfehler.
Zwei aufeinanderfolgende Zeichenfolgenliterale werden verkettet. Vermutlich wird geprüft, ob name
ist ein String-Literal. Ist dies nicht der Fall, meldet der Compiler einen Fehler.
(void)
cast unterdrückt Warnungen wie “Anweisung ohne Wirkung”.
Wenn ich mir den Code ansehe, glaube ich, dass der Zweck darin besteht, ihn anrufen zu lassen getenv
Beim ersten Aufruf das Ergebnis zwischenspeichern und danach das zwischengespeicherte Ergebnis verwenden, ohne aufrufen zu müssen getenv
mehr. Wenn getenv
mit einem String-Literal verwendet wird, fragen alle nachfolgenden Aufrufe nach derselben Umgebungsvariable; Wenn nichts diese Umgebungsvariable ändern könnte, würden sie folglich dasselbe Ergebnis zurückgeben. Wenn dem Code ein Zeiger auf eine Zeichenfolge gegeben würde, die sich später geändert hat, wäre das zwischengespeicherte Ergebnis wahrscheinlich nicht korrekt für die neue Zeichenfolge, daher besteht der Zweck des “”-Tricks darin, sicherzustellen, dass dies nicht passieren kann.
Da jedem möglichen String-Literal eine eigene statische Variable zugeordnet werden müsste, lässt sich das angegebene Code-Snippet nicht sinnvoll in eine Funktion umwandeln. Andererseits scheint die Menge an Code, die für jede Wiederholung benötigt wird, etwas viel zu sein. Wenn dieselbe Variable an mehr als einer Stelle im Code getestet wird, könnte jede davon mit einem eigenen Satz von Variablen und Umgebungsprüfungscode enden.
Abhängig davon, wie die Funktion verwendet wird, kann sie am Ende viel schneller sein als Code, der bei jedem Aufruf eine Umgebungsvariable testen muss, und sie kann innerhalb einer Funktion verwendet werden, die innerhalb einer Schleife ohne vorherige Einrichtung aufgerufen wird (if Client-Code, der eine “Advance Setup”-Funktion genannt wird, sollte die Namenssuche dort durchgeführt werden, wodurch die Notwendigkeit entfällt, innerhalb der Schleife zu prüfen, ob die Suche durchgeführt wurde).
Ich glaube nicht, dass es eine Erweiterung ist…
– Eugen Sch.
30. September 2016 um 13:42 Uhr
@EugenSch. Die spezifische Zeile, auf die ich mich bezog, ist es nicht, aber der Kontext, in dem es verwendet wurde, ist 🙂
– OMGtechy
30. September 2016 um 13:44 Uhr
Naja, dann ist der Titel wohl etwas irreführend..
– Eugen Sch.
30. September 2016 um 13:45 Uhr
@OMGtechy, woher kommt das Makro? (aus Neugier)
– Ilkkachu
2. Oktober 2016 um 7:34 Uhr
Vielleicht ist eine klarere Alternative
(void) "Must be a string literal: " name;
die die Absicht dokumentiert und auch eine selbstdokumentierende Fehlermeldung erzeugen sollte. Ein guter Compiler sollte auch den String in der Binärdatei wegoptimieren.– chi
2. Oktober 2016 um 12:10 Uhr