Was bedeutet (void) “” name in einem GNU C-Makro envSet(name)?

Lesezeit: 6 Minuten

Benutzeravatar von OMGtechy
OMGtechy

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?

  • 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

Benutzeravatar von Lundin
Lundin

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.

  • Erwähnenswert ist das vorangestellte by (void) ist, die “unbenutzte” (oder was auch immer) Warnung zum Schweigen zu bringen.

    – Eugen Sch.

    30. September 2016 um 13:26 Uhr


  • Und vielleicht auch erwähnenswert, dass dies die Tatsache nutzt, dass benachbarte String-Literale vom Präprozessor verkettet werden, es also nicht funktioniert, wenn die rechte Seite (name) ist kein Zeichenfolgenliteral. Die Umwandlung wird auf das Ergebnis der Verkettung angewendet, nicht auf "" von selbst. Edit: oh, habe die andere Antwort nicht gesehen. Heh.

    – abschalten

    30. September 2016 um 13:38 Uhr


  • Technisch gesehen findet eine String-Literal-Verkettung statt nach der Präprozessor aber Vor alles andere. Es bekommt eine Übersetzungsphase für sich alleine (Nummer 6). Am offensichtlichsten wird dies dadurch sichtbar, dass sie nicht zusammengeführt werden -E ausgegeben, und Sie können es auch mit verschiedenen Makrotricks beobachten (Makroerweiterung ist Phase 4).

    – zol

    30. September 2016 um 14:35 Uhr

  • Mein Kommentar zur Antwort von @ milleniumbug gilt auch hier.

    – PJTrail

    30. September 2016 um 15:13 Uhr

  • @PJTraill Ich erwähne es hauptsächlich für Leute, die verwirrt sein könnten, wenn sie Zeichenfolgenliterale sehen nicht einverleibt werden -E Ausgang.

    – zol

    30. September 2016 um 15:57 Uhr

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”.

  • danke, ich habe das andere akzeptiert, weil es ein Beispiel dafür lieferte, wie die PP damit umgehen würde 🙂

    – OMGtechy

    30. September 2016 um 13:37 Uhr

  • @OMGtechy im Allgemeinen steht es Ihnen frei, jede Antwort zu akzeptieren, ohne eine Entschuldigung anzugeben. Sag nur… 🙂

    – Maschine_1

    30. September 2016 um 13:53 Uhr

  • Es sieht so aus, als ob es nicht funktioniert envSet(+1). Man würde außerdem erwarten getenv(name) um den Compiler zur Validierung zu veranlassen name es sei denn, ich verwende selbstmörderisch schwache Überprüfungsoptionen, was mich fragen lässt, ob dies für eine besondere Umgebung oder nur eine seltsame Übung gedacht ist.

    – PJTrail

    30. September 2016 um 15:12 Uhr


  • @machine_1 Ich möchte nur höflich sein, wenn sich jemand die Zeit genommen hat, meine Frage zu beantworten

    – OMGtechy

    30. September 2016 um 17:19 Uhr

  • @milleniumbug: Wenn eine bestimmte Erweiterung des Makros zum ersten Mal ausgeführt wird, wird es “getenv” aufrufen. Wenn es erneut ausgeführt wird, ruft es “getenv” nicht erneut auf, sondern liefert einfach das Ergebnis, das es beim ersten Mal geliefert hat. Das ist eine nützliche Optimierung, vorausgesetzt, dass sich weder die Umgebung noch der übergebene String ändern. Es wäre jedoch eine schlechte Idee, wenn sich der übergebene String zwischen den Aufrufen ändern könnte. Zeichenfolgenliterale ändern sich im Allgemeinen garantiert nicht zwischen Aufrufen und stellen die überwiegende Mehrheit der Anwendungsfälle dar, für die eine Funktion wie diese geeignet wäre.

    – Superkatze

    30. September 2016 um 20:17 Uhr

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).

  • Dies ist in der Tat der Kontext, in dem es verwendet wird, und warum 🙂

    – OMGtechy

    1. Oktober 2016 um 20:51 Uhr

  • Vielen Dank für die bisher gründlichste und aufschlussreichste Antwort. Ich kann nicht umhin zu denken, dass …static const char * const name_const = name; /* Require a compile-time constant */ const char * value = getenv (name_const);… hätte dasselbe viel deutlicher erreicht! Oder übersehe ich etwas?

    – PJTrail

    2. Oktober 2016 um 16:27 Uhr


  • @PJTrail: Gegeben char foo[16];Ich denke, dass Ansatz akzeptieren würde (const char*)fooobwohl der Inhalt von foo zwischen Abfragen willkürlich geändert werden könnten.

    – Superkatze

    2. Oktober 2016 um 16:31 Uhr


  • Ich denke, Sie haben Recht, obwohl ein vernünftiger Compiler, der vernünftig verwendet wird, warnen sollte, dass Sie wegwerfen const. Und mutwillige C-Benutzer können sich jederzeit in die Grube werfen, wo der Wurm nagt und das Feuer für immer brennt.

    – PJTrail

    2. Oktober 2016 um 16:36 Uhr

  • @PJTrail: Wenn keine Besetzung vorhanden ist, Zuweisung der Adresse von foo wäre eine Einschränkungsverletzung. Die Besetzung wird jedoch im Allgemeinen jede Diagonsik unterdrücken. Auch wenn es eine union mit beiden a const-qualifiziertes und nicht qualifiziertes Mitglied von ansonsten identischen Typen, ich denke, das Schreiben über das nicht qualifizierte Mitglied und das Lesen über die qualifizierten Mitglieder wäre ein definiertes Verhalten, von dem jedoch nicht erwartet wird, dass es zu einer Diagnose führt.

    – Superkatze

    2. Oktober 2016 um 16:48 Uhr

1414960cookie-checkWas bedeutet (void) “” name in einem GNU C-Makro envSet(name)?

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

Privacy policy