C-Struktur-Initialisierung mit Labels. Es funktioniert, aber wie?

Lesezeit: 4 Minuten

Benutzeravatar von Andrew Cottrell
Andreas Cottrell

Ich habe gestern einen Struct-Initialisierungscode gefunden, der mich für eine Schleife geworfen hat. Hier ist ein Beispiel:

typedef struct { int first; int second; } TEST_STRUCT;
void testFunc() {
    TEST_STRUCT test = {
        second: 2,
        first:  1
    };
    printf("test.first=%d test.second=%d\n", test.first, test.second);
}

Überraschenderweise (für mich) ist hier die Ausgabe:

-> testFunc
test.first=1 test.second=2

Wie Sie sehen können, wird die Struktur ordnungsgemäß initialisiert. Mir war nicht bewusst, dass beschriftete Aussagen so verwendet werden können. Ich habe mehrere andere Möglichkeiten zur Strukturinitialisierung gesehen, aber ich habe in keinem der Online-C-FAQs Beispiele für diese Art der Strukturinitialisierung gefunden. Weiß jemand wie/warum das funktioniert?

Benutzeravatar von sigjuice
Sigisaft

Hier ist der Abschnitt des gcc-Handbuchs, der die Syntax der designierten Initialisierer für Strukturen und Arrays erklärt:

Geben Sie in einem Strukturinitialisierer den Namen eines zu initialisierenden Felds mit ‘.Feldname =‘ vor dem Elementwert. Zum Beispiel bei folgender Struktur:

 struct point { int x, y; };

folgende Initialisierung

 struct point p = { .y = yvalue, .x = xvalue }; 

ist äquivalent zu

 struct point p = { xvalue, yvalue }; 

Eine andere Syntax, die die gleiche Bedeutung hat und seit GCC 2.5 veraltet ist, ist ‘Feldname:‘, wie hier gezeigt:

 struct point p = { y: yvalue, x: xvalue };

Die entsprechende Seite ist zu finden hier.

Ihr Compiler sollte eine ähnliche Dokumentation haben.

  • Ausgezeichnet, diese Dokumentation erklärt die Syntax klar: Eine andere Syntax, die die gleiche Bedeutung hat und seit GCC 2.5 veraltet ist, ist `fieldname:’, wie hier gezeigt: struct point p = { y: yvalue, x: xvalue };

    – Andrew Cottrell

    21. Oktober 2009 um 15:31 Uhr

  • @AndrewCottrell, diese Syntax “fieldname:” sieht für mich so natürlich (und vorzuziehen) aus, haben Sie eine Idee, warum sie als veraltet angesehen werden sollte?

    – Rick

    12. Juni 2017 um 4:25 Uhr

  • @rick die Syntax “fieldname:” ist eine gcc-Erweiterung und war noch nie Teil eines ISO-C-Standards.

    – Sigissaft

    12. Juni 2017 um 5:51 Uhr


Benutzeravatar von ndim
ndim

Dies sind weder Etiketten noch Bitfelder.

Dies ist eine Syntax zum Initialisieren von Strukturmitgliedern aus der Zeit vor C99. Es ist nicht standardisiert, aber zB in gcc verfügbar.

typedef struct { int y; int x; } POINT;
POINT p = { x: 1, y: 17 };

In C99 wurde zum ersten Mal in einem Standard eine Syntax zum Initialisieren bestimmter Strukturmitglieder eingeführt, aber sie sieht etwas anders aus:

typedef struct { int y; int x; } POINT;
POINT p = { .x = 1, .y = 17 };

  • Ja, ich war mir des vorgesehenen Initialisierungsformats bewusst. Leider ist dieses Format nicht mit C++ kompatibel! (Nicht in meinen Tests sowieso.) Danke für die Antwort. Gut zu wissen, dass dies nicht standardisiert ist.

    – Andrew Cottrell

    21. Oktober 2009 um 15:08 Uhr

  • @Andrew du hast in deiner Frage nie etwas über C++ gesagt

    – Pferdemensch

    17. Dezember 2009 um 11:23 Uhr

Ja, wie oben erwähnt, sind dies designierte Initialisierer, die Standard-C sind, obwohl Sie auf die Verwendung von Punkten anstelle von Doppelpunkten umsteigen sollten. Und wie Sie bemerken, stecken die meisten Bücher da draußen immer noch irgendwo um 1984 herum in ihrer Syntax fest und erwähnen sie nicht. Weitere lustige Fakten:

–Wenn bestimmte Initialisierer verwendet werden, wird alles, was nicht angegeben ist, mit Null initialisiert. Dies hilft bei außergewöhnlich großen Strukturen, z.

typedef struct {
   double a, b, c, d, e;
   char label[100];
} too_many_type;

too_many_type tm = {.a = 1, .e = 2, .b=1.5};
assert(tm.a + tm.b + tm.c + tm.d + tm.e == 4.5);
assert(!strlen(label));

–Sie können auch die zusammengesetzte Literalform verwenden, um diese Form in einer Nicht-Initialisierungszeile zu verwenden, z. B.:

too_many_type tm2;
tm2 = (too_many_type) {.a = 3, .e=6};

Dies sind wirklich großartige Funktionen, die von jedem C-Compiler unterstützt werden, den ich mir vorstellen kann, da es sich um den Standard handelt. Schade, dass sie nicht so bekannt sind.

  • Die alternative Syntax (mit Doppelpunkten) sieht für mich so natürlich und vorzuziehen aus. Können Sie erklären, warum wir auf die Verwendung von Punkten anstelle von Doppelpunkten umsteigen sollten?

    – Rick

    12. Juni 2017 um 4:28 Uhr

Benutzeravatar von Thomas Padron-McCarthy
Thomas Padron-McCarthy

Es handelt sich nicht wirklich um “beschriftete Anweisungen”, sondern um eine Möglichkeit, den benannten Feldern in der Struktur Anfangswerte zu geben.

Gcc warnt vor “veralteter Verwendung des designierten Initialisierers mit ‘:'”, und in C99 sollten Sie stattdessen schreiben:

    TEST_STRUCT test = {
        .second = 2,
        .first =  1
    };

Benutzeravatar von pmg
pmg

Diese Syntax ist nicht durch den C-Standard definiert. Abschnitt 6.7.8 Initialization sagt

         designation:
                designator-list =
         designator-list:
                designator
                designator-list designator
         designator:
                [ constant-expression ]
                . identifier

Wenn Ihr Compiler eine Bezeichnung mit einem Doppelpunkt ohne Diagnosemeldung akzeptiert, bedeutet dies, dass Ihr Compiler nicht standardkonform ist (oder nicht so konfiguriert ist).

1407410cookie-checkC-Struktur-Initialisierung mit Labels. Es funktioniert, aber wie?

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

Privacy policy