Anonyme Vereinigung innerhalb der Struktur nicht in c99?

Lesezeit: 8 Minuten

Benutzeravatar von Martin
Martin

Hier ist ein sehr vereinfachter Code des Problems, das ich habe:

enum node_type {
    t_int, t_double
};

struct int_node {
    int value;
};

struct double_node {
    double value;
};

struct node {
    enum node_type type;
    union {
        struct int_node int_n;
        struct double_node double_n;
    };
};

int main(void) {
    struct int_node i;
    i.value = 10;
    struct node n;
    n.type = t_int;
    n.int_n = i;
    return 0;
}

Und was ich nicht verstehe ist folgendes:

$ cc us.c 
$ cc -std=c99 us.c 
us.c:18:4: warning: declaration does not declare anything
us.c: In function ‘main’:
us.c:26:4: error: ‘struct node’ has no member named ‘int_n’

Verwenden GCC ohne -std Option kompiliert den obigen Code ohne Probleme (und der ähnliche Code funktioniert ziemlich gut), aber es scheint so c99 lässt diese Technik nicht zu. Warum ist das so und ist es möglich, es zu machen? c99 (oder c89, c90) kompatibel? Vielen Dank.

  • Nur eine Anmerkung, clang kompiliert gegebenen Code mit und ohne -std=c99 lautlos, ohne Fehler und Warnungen.

    – Martin

    12. Juli 2010 um 11:58 Uhr

R.. GitHub STOP HELPING ICEs Benutzeravatar
R.. GitHub HÖREN SIE AUF, ICE ZU HELFEN

Anonyme Unions sind eine GNU-Erweiterung, nicht Teil einer Standardversion der C-Sprache. Sie können -std=gnu99 oder ähnliches für c99+GNU-Erweiterungen verwenden, aber es ist am besten, richtiges C zu schreiben und sich nicht auf Erweiterungen zu verlassen, die nichts als syntaktischen Zucker liefern …

Bearbeiten: Anonyme Gewerkschaften wurden in C11 hinzugefügt, sodass sie jetzt ein Standardbestandteil der Sprache sind. Vermutlich GCCs -std=c11 lässt Sie sie verwenden.

  • Update 2019, keine Verwendung erforderlich -std=c11 mit aktuellen stabilen Versionen für anonym struct oder union. Ich bin mir nicht sicher, welche Version vor GCC 8.2 als Standard übernommen wurde.

    – Undefiniertes Verhalten

    26. Februar 2019 um 13:21 Uhr

  • @UndefinedBehavior GCC 5 wird bereits erweitert __STDC_VERSION__ wie 201112L, während GCC 4.8 es überhaupt nicht erweitert – beide mit Standardeinstellungen. Anscheinend ist es also GCC 5, das standardmäßig auf C11 (eigentlich gnu11) eingestellt ist.

    – Ruslan

    26. August 2020 um 14:06 Uhr

Benutzeravatar von bk
schwarz

Ich finde diese Frage etwa anderthalb Jahre nach allen anderen, daher kann ich eine andere Antwort geben: Anonyme Strukturen sind nicht im C99-Standard, aber im C11-Standard. GCC und Clang unterstützen dies bereits (der C11-Standard scheint die Funktion von Microsoft aufgehoben zu haben, und GCC bietet seit einiger Zeit Unterstützung für einige MSFT-Erweiterungen).

  • Die Ironie besteht darin, dass die Semantik anonymer Strukturen und Vereinigungen in Dennis Ritchies C-Compiler von 1974 verfügbar war, und ich glaube, gcc hatte anonyme Strukturen und Vereinigungen in den Tagen vor dem C89-Standard unterstützt. Einige Leute scheinen zu denken, dass es sich um ein neues Feature handelt, aber es stellt lediglich eine wiedergewonnene Fähigkeit dar, die niemals hätte verloren gehen dürfen.

    – Superkatze

    26. Mai 2018 um 17:55 Uhr

Nun, die Lösung bestand darin, die Instanz der Union zu benennen (die als Datentyp anonym bleiben kann) und diesen Namen dann als Proxy zu verwenden.

$ diff -u old_us.c us.c 
--- old_us.c    2010-07-12 13:49:25.000000000 +0200
+++ us.c        2010-07-12 13:49:02.000000000 +0200
@@ -15,7 +15,7 @@
   union {
     struct int_node int_n;
     struct double_node double_n;
-  };
+  } data;
 };

 int main(void) {
@@ -23,6 +23,6 @@
   i.value = 10;
   struct node n;
   n.type = t_int;
-  n.int_n = i;
+  n.data.int_n = i;
   return 0;
 }

Jetzt kompiliert es als c99 ohne Probleme.

$ cc -std=c99 us.c 
$ 

Hinweis: Ich bin mit dieser Lösung sowieso nicht glücklich.

  • Du solltest glücklich sein! Dies ist die Standardmethode für den Zugriff auf Gewerkschaftsmitglieder, die seit dem 1. Januar 1970 garantiert mit jedem C-Compiler funktioniert.

    – Jens

    23. August 2012 um 7:11 Uhr

  • Es verfälscht den Code etwas, keine Ahnung, warum es nicht in K&R C enthalten war, scheint mir ein einfaches und nützliches Feature zu sein … Wie auch immer, ich verwende die gleiche Proxy-Methode, aber definiere Makros, um das ganze Tippen zu vermeiden.

    – Arran Cudbard-Bell

    3. Dezember 2014 um 3:16 Uhr


  • Mir ist klar, dass dies ein sehr alter Beitrag ist, aber das Kopieren des tatsächlichen Codes anstelle eines Diff-Patches ist viel besser lesbar.

    – jap

    25. April 2016 um 1:10 Uhr

  • @ysap aber wie hast du dann den unterschied erkannt?

    – binki

    20. August 2016 um 1:21 Uhr

  • @binki vielleicht brauchen wir einen DiffOverflow, wo Leute Codeschnipsel posten und Antworten aus Diffs bestehen, die sie verbessern (möglicherweise aufeinander basierend) 🙂

    – Thomas

    22. August 2016 um 10:40 Uhr

Benutzeravatar von Undefined Behaviour
Undefiniertes Verhalten

Nur zur Klärung von anonym struct oder anonym union.

C11

6.7.2.1 Struktur- und Vereinigungsspezifizierer

Ein namenloses Mitglied dessen Typbezeichner ein Strukturbezeichner mit ist
keine Markierung heißt ein anonyme Struktur; ein namenloses Mitglied dessen Typbezeichner ein Union-Bezeichner mit ist keine Markierung heißt ein anonyme Vereinigung. Die Mitglieder einer anonymen Struktur oder Vereinigung werden als Mitglieder der enthaltenden Struktur oder Vereinigung betrachtet. Dies gilt rekursiv, wenn die enthaltende Struktur oder Union ebenfalls anonym ist.

C99 Es gibt keine anonyme Struktur oder Union

Vereinfacht: Typbezeichner Kennung { Deklarationsliste } Stichworte ;

  • Typbezeichner: struct oder union;
  • Kennung: optional, Ihr benutzerdefinierter Name für die struct oder union;
  • Deklarationsliste: Mitglieder, Ihre Variablen, anonym struct und anonym union
  • Stichworte: Optional. Wenn Sie eine haben typedef vor dem Typbezeichnerdas Stichworte Alias ​​sind und nicht Stichworte.

Es ist eine anonyme struct oder anonym union nur wenn es keinen Bezeichner und kein Tag hat und in einem anderen existiert struct oder union.

struct s {
    struct { int x; };     // Anonymous struct, no identifier and no tag
    struct a { int x; };   // NOT Anonymous struct, has an identifier 'a'
    struct { int x; } b;   // NOT Anonymous struct, has a tag 'b'
    struct c { int x; } C; // NOT Anonymous struct
};

struct s {
    union { int x; };     // Anonymous union, no identifier and no tag
    union a { int x; };   // NOT Anonymous union, has an identifier 'a'
    union { int x; } b;   // NOT Anonymous union, has a tag 'b'
    union c { int x; } C; // NOT Anonymous union
};

typedef hell: wenn du eine hast typedef Der Tag-Teil ist kein Tag mehr, sondern ein Alias ​​für diesen Typ.

struct a { int x; } A; // 'A' is a tag
union a { int x; } A;  // 'A' is a tag

// But if you use this way
typedef struct b { int x; } B; // 'B' is NOT a tag. It is an alias to struct 'b'
typedef union b { int x; } B;  // 'B' is NOT a tag. It is an alias to union 'b'

// Usage
A.x = 10; // A tag you can use without having to declare a new variable

B.x = 10; // Does not work

B bb; // Because 'B' is an alias, you have to declare a new variable
bb.x = 10;

Das Beispiel unten ändert sich einfach struct zum unionfunktioniert genauso.

struct a { int x; }; // Regular complete struct type
typedef struct a aa; // Alias 'aa' for the struct 'a'

struct { int x; } b; // Tag 'b'
typedef struct b bb; // Compile, but unusable.

struct c { int x; } C; // identifier or struct name 'c' and tag 'C'
typedef struct { int x; } d; // Alias 'd'
typedef struct e { int x; } ee; // struct 'e' and alias 'ee'

Benutzeravatar von Svisstack
Svisstack

Union muss einen Namen haben und wie folgt deklariert werden:

union UPair {
    struct int_node int_n;
    struct double_node double_n;
};

UPair X;
X.int_n.value = 12;

  • Nicht in C11, aber in C99 ja. Aber da wir die Drei-Jahres-Marke seit seiner Veröffentlichung überschritten haben, ist es vielleicht an der Zeit, -std=c11 zu übergeben :).

    – Arran Cudbard-Bell

    3. Dezember 2014 um 3:14 Uhr


  • Ihr Codebeispiel ist in C++, nicht in C. union UPair erklärt nicht a UPair Typ in C. Die Namespaces für Tags und Typen sind in C getrennt, aber nicht in C++.

    – Patrick Schlüter

    14. September 2018 um 10:54 Uhr

Benutzeravatar von theJPster
der JPster

Eine andere Lösung besteht darin, den gemeinsamen Header-Wert (enum node_type type) in jede Struktur und machen Sie Ihre Struktur der obersten Ebene zu einer Union. Es ist nicht gerade “Don’t Repeat Yourself”, aber es vermeidet sowohl anonyme Vereinigungen als auch unbequem aussehende Proxy-Werte.

enum node_type {
    t_int, t_double
};
struct int_node {
    enum node_type type;
    int value;
};
struct double_node {
    enum node_type type;
    double value;
};
union node {
    enum node_type type;
    struct int_node int_n;
    struct double_node double_n;
};

int main(void) {
    union node n;
    n.type = t_int; // or n.int_n.type = t_int;
    n.int_n.value = 10;
    return 0;
}

  • Nicht in C11, aber in C99 ja. Aber da wir die Drei-Jahres-Marke seit seiner Veröffentlichung überschritten haben, ist es vielleicht an der Zeit, -std=c11 zu übergeben :).

    – Arran Cudbard-Bell

    3. Dezember 2014 um 3:14 Uhr


  • Ihr Codebeispiel ist in C++, nicht in C. union UPair erklärt nicht a UPair Typ in C. Die Namespaces für Tags und Typen sind in C getrennt, aber nicht in C++.

    – Patrick Schlüter

    14. September 2018 um 10:54 Uhr

Benutzeravatar von Cellcon
Cellkon

Wenn ich mir 6.2.7.1 von C99 anschaue, sehe ich, dass die Kennung optional ist:

struct-or-union-specifier:
    struct-or-union identifier-opt { struct-declaration-list }
    struct-or-union identifier

struct-or-union:
    struct
    union

struct-declaration-list:
    struct-declaration
    struct-declaration-list struct-declaration

struct-declaration:
    specifier-qualifier-list struct-declarator-list ;

specifier-qualifier-list:
    type-specifier specifier-qualifier-list-opt
    type-qualifier specifier-qualifier-list-opt

Ich habe auf und ab gesucht und kann keinen Hinweis darauf finden, dass anonyme Gewerkschaften gegen die Spezifikation verstoßen. Das ganze Suffix -opt zeigt in diesem Fall an, dass das Ding identifier ist gemäß 6.1 optional.

  • Ich glaube hier liegt ein Missverständnis vor. Der Bezeichner für eine Struktur oder Union Schild ist optional, aber nicht der Bezeichner, der deklariert wird. Das können Sie nicht sagen union { ... }; innerhalb eines Aggregats aus demselben Grund, aus dem Sie es nicht sagen können int;. Im Union-Fall erlauben Compiler-Erweiterungen dies, da Sie Bezeichner in der verwenden können {...} Teil bei Verwendung einer anonymen Union.

    – Jens

    22. August 2012 um 8:39 Uhr


1410940cookie-checkAnonyme Vereinigung innerhalb der Struktur nicht in c99?

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

Privacy policy