Warum verbietet C ++ anonyme Strukturen?

91

Einige C ++ - Compiler erlauben anonyme Vereinigungen und Strukturen als Erweiterung von Standard-C ++. Es ist ein bisschen syntaktischer Zucker, der gelegentlich sehr hilfreich ist.

Was ist die Begründung, die verhindert, dass dies Teil des Standards ist? Gibt es eine technische Straßensperre? Eine philosophische? Oder einfach nicht genug, um es zu rechtfertigen?

Hier ist ein Beispiel von dem, wovon ich spreche:

struct vector3 {
  union {
    struct {
      float x;
      float y;
      float z;
    };
    float v[3];
  };
};

Mein Compiler akzeptiert dies, warnt jedoch davor, dass "nameless struct / union" eine nicht standardmäßige Erweiterung von C ++ ist .

Adrian McCarthy
quelle
3
Offensichtlich gibt es einige Verwirrung darüber, was Sie meinen. Könnten Sie bitte ein Beispiel für Code angeben, der nur aufgrund einer Compiler-Erweiterung kompiliert wird?
Rob Kennedy
72
Beachten Sie, dass es zwei Konzepte gibt, die ähnlich klingen, sich jedoch stark unterscheiden: unbenannte Strukturen und anonyme Strukturen . Das erste ist dieses, das C ++ unterstützt: struct { int i; } a; a.i = 0;(der Typ hat keinen Namen). Der zweite ist dieser, den C ++ nicht unterstützt: struct { int i; }; i = 0;(Der Typ hat keinen Namen und entweicht in den umgebenden Bereich). C ++, jedoch funktioniert sowohl unbenannte und anonym unterstützen Gewerkschaften .
Johannes Schaub - litb
Dies sieht aus wie die ziemlich interessante VMMLib-Vektorbibliothek. Ich glaube, das Problem ist, dass die Gewerkschaft eine unbenannte Struktur enthält, aber ich bin mir nicht sicher.
Greyfade
1
FWIW Es ist "anonmyous", nicht "unbenannt", und Gewerkschaften werden unterstützt, wie litb sagt. stackoverflow.com/q/14248044/560648
Leichtigkeitsrennen im Orbit
1
@AdrianMcCarthy: Das ist in Ordnung (FSVO "gut"; lästiger Compiler ist kryptisch), aber genau "unbenannt" ist ein nicht verwandtes Standardkonzept.
Leichtigkeitsrennen im Orbit

Antworten:

49

Wie andere bereits betont haben, sind anonyme Gewerkschaften in Standard-C ++ zulässig, anonyme Strukturen jedoch nicht.

Der Grund dafür ist, dass C anonyme Gewerkschaften unterstützt, aber keine anonymen Strukturen *. Daher unterstützt C ++ die ersteren aus Kompatibilitätsgründen, die letzteren jedoch nicht, da sie aus Kompatibilitätsgründen nicht benötigt werden.

Darüber hinaus sind anonyme Strukturen in C ++ nicht sehr nützlich. Die Verwendung, die Sie demonstrieren, um eine Struktur mit drei Floats zu haben, auf die entweder von .v[i]oder verwiesen werden kann .x, .yführt .zmeines Erachtens zu einem undefinierten Verhalten in C ++. In C ++ können Sie beispielsweise nicht an ein Mitglied einer Gewerkschaft schreiben .v[1]und dann beispielsweise von einem anderen Mitglied lesen .y. Obwohl Code, der dies tut, nicht ungewöhnlich ist, ist er nicht wirklich gut definiert.

Die Funktionen von C ++ für benutzerdefinierte Typen bieten alternative Lösungen. Beispielsweise:

struct vector3 {
  float v[3];
  float &operator[] (int i) { return v[i]; }
  float &x() { return v[0]; }
  float &y() { return v[1]; }
  float &z() { return v[2]; }
};

* C11 fügt anscheinend anonyme Strukturen hinzu, sodass eine zukünftige Überarbeitung von C ++ sie möglicherweise hinzufügen kann.

bames53
quelle
2
+1: Mein Beispiel basiert auf undefiniertem Verhalten in C ++ - etwas, das mir beim Schreiben der Frage nicht bewusst war.
Adrian McCarthy
2
"In C ++ können Sie nicht [...] an ein Mitglied einer Gewerkschaft schreiben und dann von einem anderen Mitglied lesen" - es sei denn , diese Mitglieder sind Objekte mit Standardlayout und teilen eine gemeinsame Anfangssequenz ihrer eigenen Mitglieder, und Sie ' Schreiben / Lesen ihrer Mitglieder innerhalb der gemeinsamen Anfangssequenz. Das ist erlaubt (dh definiert).
underscore_d
5
@underscore_d: Ja, wenn die Typen Standardlayout mit einer gemeinsamen Anfangssequenz sind. Eine Struktur kann jedoch niemals auf diese Weise einen Alias ​​mit einem Array bilden , da die Regeln der "gemeinsamen Anfangssequenz" von C ++ besagen, dass eine gemeinsame Anfangssequenz nur zwischen Strukturen bestehen kann . Arrays werden nicht erwähnt, daher können sie keinen solchen Alias ​​haben.
Nicol Bolas
@NicolBolas Oh, haha ​​- glauben Sie mir - ich habe mir oft gewünscht, dass Arrays und andere Grundelemente in dieser Zulage enthalten sind! Aber ich habe nicht viel über die möglichen praktischen Einschränkungen nachgedacht, daher ist es wahrscheinlich nicht so einfach, wie es derzeit scheint. Mein Kommentar war allgemeiner, hätte aber das Risiko eingehen können, durch Auslassung zu implizieren, dass ich dachte, dass Arrays darin enthalten sind. Vielen Dank, dass Sie das hinzugefügt haben.
underscore_d
"Der Grund dafür ist, dass C anonyme Gewerkschaften unterstützt, aber keine anonymen Strukturen" - Nein. In Ihrer Fußnote wird klargestellt, dass Sie hier über C99 oder früher gesprochen haben. Der Begriff "anonyme Vereinigung" kommt im C99-Standard nirgendwo vor. GCC behauptet in einer Diagnose (mit -std = c99 -pedantischen Optionen), dass "ISO C99 keine unbenannten Strukturen / Gewerkschaften unterstützt". Der Standard erwähnt nichts über unbenannte Mitglieder außer unbenannten Bitfeldern. Ich bin nicht ganz sicher, ob Strukturdeklarationen Deklarationen sind, aber wenn ja, sind anonyme Gewerkschaften eine Einschränkungsverletzung gemäß 6.7p2, bestenfalls undefiniert.
21

Ich werde sagen, Sie können Ihre vector3Erklärung bereinigen, indem Sie einfach a verwendenunion

union vector3 {
  struct { float x, y, z; } ;
  float v[3] ;
} ;

Sicher, anonyme Strukturen waren eine MSVC-Erweiterung . Aber ISO C11 erlaubt es jetzt und gcc erlaubt es , ebenso wie Apples llvm-Compiler.

Warum in C11 und nicht in C ++ 11? Ich bin mir nicht sicher, aber praktisch die meisten (gcc ++, MSVC ++ und Apples C ++ - Compiler) C ++ - Compiler unterstützen sie.

Bobobobo
quelle
1
+1 für aktualisierte Informationen. Der Grund, warum ich eine äußere Struktur hatte, war, dass der "echte Code" auch Methoden hatte.
Adrian McCarthy
Die einzigen Dinge, die Sie mit einer Gewerkschaft nicht tun können, sind statische Datenelemente oder die Verwendung der Vererbung .
Bobobobo
2
Vielen Dank. Ich habe nie erfahren, dass eine Gewerkschaft wie eine Struktur oder Klasse verwendet werden kann.
Adrian McCarthy
Ich weiß, dass Sun Studio vor C ++ 11 standardmäßig keine anonyme Struktur unterstützt hat. Wenn Sie plattformübergreifenden Code schreiben und Compiler nicht auf C + 11 aktualisiert werden, verwenden Sie keine anonyme Struktur.
Irsis
6

Nicht sicher was du meinst. Abschnitt 9.5 der C ++ - Spezifikation, Abschnitt 2:

Eine Vereinigung der Form

union { member-specification } ;

wird eine anonyme Vereinigung genannt; Es definiert ein unbenanntes Objekt vom unbenannten Typ.

Sie können solche Dinge auch tun:

void foo()
{
  typedef
  struct { // unnamed, is that what you mean by anonymous?
    int a;
    char b;
  } MyStructType; // this is more of a "C" style, but valid C++ nonetheless

  struct { // an anonymous struct, not even typedef'd
    double x;
    double y;
  } point = { 1.0, 3.4 };
}

Nicht immer sehr nützlich ... obwohl manchmal nützlich in bösen Makrodefinitionen.

Dan
quelle
11
-1, weil es heißt, dass es eine anonyme Struktur definiert. Siehe Kommentare oben zu der Frage - Sie definieren eine unbenannte Struktur, keine anonyme.
Johannes Schaub - litb
1

Gewerkschaften können anonym sein; siehe Standard, 9.5 Absatz 2.

Welchen Zweck sehen Sie in einer anonymen Struktur oder Klasse als erfüllend? Bevor ich darüber spekuliere, warum etwas nicht im Standard enthalten ist, möchte ich eine Vorstellung davon haben, warum es so sein sollte, und ich sehe keine Verwendung für eine anonyme Struktur.

David Thornley
quelle
1

Basierend auf der Bearbeitung, den Kommentaren und diesem MSDN-Artikel: Anonyme Strukturen riskiere ich eine Vermutung - es passt schlecht zum Konzept der Kapselung. Ich würde nicht erwarten, dass ein Mitglied einer Klasse mit meinem Klassennamensraum herumspielt, außer nur ein Mitglied hinzuzufügen. Darüber hinaus können Änderungen an der anonymen Struktur meine Klasse ohne Erlaubnis beeinflussen.

JonM
quelle
1
Aufgrund der Art und Weise, wie anonyme Strukturen / Gewerkschaften erstellt werden (es handelt sich um eine spezielle Inline-Syntax, die nur durch ein Makro ausgeblendet werden kann), können Sie sich nicht wundern, dass ein von Ihnen verwendetes Mitglied ein anonymes Mitglied ist. Ich halte diese Argumentation also nicht für sinnvoll. Der eigentliche Grund ist , dass anonyme Gewerkschaften sind in C ++ unterstützt, nur für C - Kompatibilität. C unterstützt keine anonymen Strukturen (bis C11) und C ++ auch nicht.
Bames53
1

Dein Code

union {
  struct {
    float x;
    float y;
    float z;
  };
  float v[3];
};

ist wie

union Foo {
   int;
   float v[3];
};

das ist sicherlich ungültig (in C99 und früher).

Der Grund ist wahrscheinlich , das Parsen zu vereinfachen (in C), da Sie in diesem Fall nur überprüfen müssen, ob der Struktur- / Vereinigungskörper nur "Deklaratoranweisungen" wie enthält

Type field;

Das sagte, GCC und „andere Compilern“ unterstützt unnamed Felder als Erweiterung.

Bearbeiten: Anonyme Strukturen werden jetzt offiziell in C11 unterstützt (§6.7.2.1 / 13).

kennytm
quelle
5
Aus einer Parsing-Perspektive denke ich nicht, dass union { ... }das anders ist als struct { ... }. Ersteres ist gültig, letzteres jedoch nicht.
Johannes Schaub - litb
3
Angesichts der absurden Schwierigkeit, C ++ im Allgemeinen zu analysieren, bezweifle ich, dass der Standard unbenannte Strukturen und Gewerkschaften verbietet, nur um das Parsen zu vereinfachen.
Adrian McCarthy
@Adrian: Ich sagte C, nicht C ++. C ++ übernimmt die Syntax von C und erweitert sie. Wahrscheinlich sehen die Entwickler von C ++ keine Notwendigkeit, unbenannte Struktur- / Gewerkschaftsmitglieder zuzulassen, damit sie sich nicht mit diesem Teil der Syntax herumschlagen.
Kennytm
@ Adrian, guter Punkt, Adrian, ich habe immer nicht gedacht, dass "zu schwer umzusetzen" jemals ein Anliegen von Bjarne und der Crew sein würde
Bobobobo
C und C ++ unterstützen beide unbenannte Gewerkschaften, daher union { ... };ist der ungültige Kommentar nicht korrekt.
Bames53