Perché il C ++ non consente le strutture anonime?


92

Alcuni compilatori C ++ consentono unioni e strutture anonime come estensione del C ++ standard. È un po 'di zucchero sintattico che a volte è molto utile.

Qual è la logica che impedisce che ciò faccia parte dello standard? C'è un ostacolo tecnico? Uno filosofico? O semplicemente non abbastanza di un bisogno per giustificarlo?

Ecco un esempio di ciò di cui sto parlando:

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

Il mio compilatore lo accetterà, ma avverte che "struct / union senza nome" è un'estensione non standard di C ++ .


3
Chiaramente c'è una certa confusione su cosa intendi. Potresti fornire un esempio di codice che viene compilato solo a causa di un'estensione del compilatore?
Rob Kennedy,

74
Si noti che ci sono due concetti che suonano simili, ma sono molto diversi: strutture senza nome e strutture anonime . Il primo è questo, supportato da C ++: struct { int i; } a; a.i = 0;(il tipo non ha nome). Il secondo è questo, che C ++ non supporta: struct { int i; }; i = 0;(il tipo non ha nome e sfugge allo scope circostante). C ++, tuttavia, non supportare entrambi senza nome e anonimi sindacati .
Johannes Schaub - litb

Sembra la libreria vettoriale VMMLib piuttosto interessante. Credo che il problema sia che l'unione contiene una struttura senza nome, ma non sono sicuro.
dissolvenza grigia

1
FWIW È "anonimo", non "senza nome", ei sindacati sono supportati come dice litb. stackoverflow.com/q/14248044/560648
Gare di leggerezza in orbita

1
@AdrianMcCarthy: Va bene (USAV "bene"; il fastidioso compilatore è criptico), ma precisamente "senza nome" è un concetto standard non correlato.
Gare di leggerezza in orbita il

Risposte:


50

Come altri hanno sottolineato, le unioni anonime sono consentite nel C ++ standard, ma le strutture anonime non lo sono.

La ragione di ciò è che C supporta unioni anonime ma non strutture anonime *, quindi C ++ supporta la prima per compatibilità ma non la seconda perché non è necessaria per la compatibilità.

Inoltre, non c'è molto uso di strutture anonime in C ++. L'uso dimostrate, per avere una struttura che contiene tre carri che è possibile fare riferimento o da .v[i], o .x, .ye .z, credo che si traduce in un comportamento indefinito in C ++. Il C ++ non ti permette di scrivere a un membro di un'unione, diciamo .v[1], e poi di leggere da un altro membro, diciamo .y. Sebbene il codice che fa ciò non sia raro, in realtà non è ben definito.

Le funzionalità di C ++ per i tipi definiti dall'utente forniscono soluzioni alternative. Per esempio:

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 apparentemente aggiunge strutture anonime, quindi una futura revisione a C ++ potrebbe aggiungerle.


2
+1: il mio esempio si basa su un comportamento indefinito in C ++, qualcosa di cui non ero a conoscenza quando ho scritto la domanda.
Adrian McCarthy

2
"Il C ++ non consente di scrivere su un membro di un'unione [...] e poi leggere da un altro membro" - a meno che detti membri non siano oggetti con layout standard e condividano una sequenza iniziale comune di membri propri, e tu ' ri-scrivere / leggere i propri membri all'interno di detta sequenza iniziale comune. Ciò è consentito (ovvero definito).
underscore_d

5
@underscore_d: Sì, se i tipi sono layout standard con una sequenza iniziale comune. Tuttavia, uno struct non può mai creare un alias con un array in questo modo, perché le regole di "sequenza iniziale comune" del C ++ affermano che una sequenza iniziale comune può essere solo tra strutture . Gli array non sono menzionati, quindi non possono essere alias in questo modo.
Nicol Bolas

@NicolBolas Oh, haha ​​- credimi - ho desiderato molte volte che gli array e altre primitive fossero inclusi in questa indennità! Ma non ho pensato molto alle possibili limitazioni pratiche su questo, quindi probabilmente non è così semplice come sembra attualmente. Il mio commento era più generale ma avrebbe potuto rischiare di implicare per omissione che pensavo che gli array fossero inclusi in questo, quindi grazie per averlo aggiunto.
underscore_d

"La ragione di ciò è che C supporta unioni anonime ma non strutture anonime" - No. La tua nota a piè di pagina chiarisce che stavi parlando di C99 o prima qui. Il termine "unione anonima" non compare da nessuna parte nello standard C99. GCC afferma in una diagnostica (con -std = c99 -pedantic opzioni) che "ISO C99 non supporta strutture / unioni senza nome". Lo standard non menziona nulla sui membri senza nome tranne i campi di bit senza nome. Non sono del tutto sicuro che le dichiarazioni di struttura siano dichiarazioni, ma se lo sono, le unioni anonime sono una violazione dei vincoli per 6.7p2, nella migliore delle ipotesi non definite.

21

Dirò che puoi ripulire la tua vector3dichiarazione semplicemente usando un fileunion

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

Certo, le strutture anonime erano un'estensione di MSVC . Ma ISO C11 ora lo consente e gcc lo consente , così come il compilatore llvm di Apple.

Perché in C11 e non in C ++ 11? Non ne sono sicuro, ma praticamente parlando la maggior parte dei compilatori C ++ (gcc ++, MSVC ++ e C ++ di Apple) li supporta.


1
+1 per informazioni aggiornate. Il motivo per cui avevo una struttura esterna era perché anche il "codice reale" aveva metodi.
Adrian McCarthy

Le uniche cose che non puoi fare con un'unione sono avere membri dati statici o usare l'ereditarietà .
bobobobo

2
Grazie. Non ho mai scoperto che un'unione potrebbe essere usata come una struttura o una classe.
Adrian McCarthy

So che Sun Studio non supportava per impostazione predefinita la struttura anonima prima di C ++ 11. Se stai scrivendo codice multipiattaforma e i compilatori non sono aggiornati a C + 11, non utilizzare struct anonimo.
irsis

6

Non sono sicuro cosa intendi. Sezione 9.5 della specifica C ++, clausola 2:

Un'unione della forma

union { member-specification } ;

è chiamata unione anonima; definisce un oggetto senza nome di tipo senza nome.

Puoi fare anche cose come questa:

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 };
}

Non sempre molto utile ... anche se a volte utile nelle definizioni di macro brutte.


11
-1 perché sta dicendo che definisce una struttura anonima. Vedi i commenti sopra sulla domanda: stai definendo una struttura senza nome, non anonima.
Johannes Schaub - litb

1

I sindacati possono essere anonimi; vedere lo Standard, 9.5 paragrafo 2.

Quale scopo consideri soddisfacente una struttura o una classe anonima? Prima di speculare sul perché qualcosa non sia nello Standard, mi piacerebbe avere un'idea del perché dovrebbe essere, e non vedo un uso per una struttura anonima.


1

Sulla base della modifica, dei commenti e di questo articolo MSDN: Strutture anonime , azzardo un'ipotesi: si adatta male al concetto di incapsulamento. Non mi aspetterei che un membro di una classe rovinasse lo spazio dei nomi della mia classe oltre alla semplice aggiunta di un membro. Inoltre, le modifiche alla struttura anonima possono influenzare la mia classe senza autorizzazione.


1
A causa del modo in cui vengono create le strutture / unioni anonime (è una sintassi inline speciale che non può essere nascosta se non da una macro) non puoi essere sorpreso dal fatto che un membro che stai utilizzando sia un membro anonimo. Quindi non credo che questo ragionamento abbia alcun senso. Il vero motivo è che le unioni anonime sono supportate in C ++, solo per compatibilità C. C non supporta strutture anonime (fino a C11) e quindi nemmeno C ++.
bames53

1

Il tuo codice

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

è come

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

che è sicuramente non valido (in C99 e prima).

Il motivo è probabilmente quello di semplificare il parsing (in C), perché in quel caso devi solo controllare che il corpo della struttura / unione abbia solo "dichiarazioni del dichiarante" come

Type field;

Detto questo, gcc e "altri compilatori" supportano i campi senza nome come estensione.

Modifica: le strutture anonime sono ora ufficialmente supportate in C11 (§6.7.2.1 / 13).


5
Dal punto di vista dell'analisi, non penso che union { ... }sia diverso da struct { ... }. Il primo è valido, ma il secondo no.
Johannes Schaub - litb

3
Considerato quanto sia assurdamente difficile analizzare il C ++ in generale, dubito che gli struct e le unioni senza nome commessi non consentiti dallo standard solo per semplificare l'analisi.
Adrian McCarthy,

@ Adrian: ho detto C, non C ++. C ++ adotta la sintassi del C e la estende. Probabilmente i creatori di C ++ non vedono la necessità di consentire membri di struct / union senza nome in modo da non interferire con quella parte della sintassi.
kennytm

@ Adrian, Buon punto Adrian, non ho sempre pensato che "troppo difficile da implementare" sarebbe mai stata una preoccupazione per Bjarne e l'equipaggio
bobobobo

C e C ++ supportano entrambi unioni senza nome, quindi il commento union { ... };non valido non è corretto.
bames53
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.