Mengapa C ++ melarang struct anonim?

93

Beberapa compiler C ++ mengizinkan unions dan struct anonim sebagai ekstensi untuk C ++ standar. Ini sedikit gula sintaksis yang terkadang sangat membantu.

Apa alasan yang mencegah ini menjadi bagian dari standar? Apakah ada hambatan teknis? Yang filosofis? Atau hanya tidak cukup kebutuhan untuk membenarkannya?

Inilah contoh dari apa yang saya bicarakan:

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

Kompiler saya akan menerima ini, tetapi ia memperingatkan bahwa "struct / union tanpa nama" adalah ekstensi non-standar untuk C ++ .

Adrian McCarthy
sumber
3
Jelas ada kebingungan tentang apa yang Anda maksud. Bisakah Anda memberikan contoh kode yang hanya dikompilasi karena ekstensi kompiler?
Rob Kennedy
75
Perhatikan bahwa ada dua konsep, yang terdengar serupa, tetapi sangat berbeda: struct tanpa nama dan struct anonim . Yang pertama adalah yang ini, yang didukung C ++: struct { int i; } a; a.i = 0;(tipe tidak memiliki nama). Yang kedua adalah yang ini, yang tidak didukung C ++ : struct { int i; }; i = 0;(tipe tidak memiliki nama, dan lolos ke lingkup sekitarnya). C ++, bagaimanapun, tidak mendukung kedua tidak disebutkan namanya dan anonim serikat .
Johannes Schaub - litb
Ini terlihat seperti pustaka vektor VMMLib yang cukup menarik. Saya yakin masalahnya adalah bahwa serikat tersebut berisi struct yang tidak disebutkan namanya, tetapi saya tidak yakin.
greyfade
1
FWIW Ini yang "anonmyous", bukan "tidak disebutkan namanya", dan serikat yang didukung sebagai litb kata. stackoverflow.com/q/14248044/560648
Balapan Ringan di Orbit
1
@AdrianMcCarthy: Tidak apa-apa (FSVO "baik-baik saja"; kompiler sial menjadi samar), tetapi tepatnya "tanpa nama" adalah konsep standar yang tidak terkait.
Balapan Ringan di Orbit

Jawaban:

50

Seperti yang telah ditunjukkan oleh orang lain, serikat anonim diizinkan dalam C ++ standar, tetapi struct anonim tidak.

Alasannya adalah karena C mendukung unions anonim tetapi bukan struct anonim *, jadi C ++ mendukung yang pertama untuk kompatibilitas tetapi bukan yang terakhir karena tidak diperlukan untuk kompatibilitas.

Selain itu, tidak banyak gunanya struct anonim di C ++. Penggunaan Anda menunjukkan, memiliki struct yang berisi tiga mengapung yang dapat disebut baik oleh .v[i], atau .x, .ydan .z, saya percaya hasil dalam perilaku undefined di C ++. C ++ tidak mengizinkan Anda untuk menulis ke salah satu anggota serikat, katakanlah .v[1], dan kemudian membaca dari anggota lain, katakanlah .y. Meskipun kode yang melakukan ini tidak jarang, sebenarnya tidak didefinisikan dengan baik.

Fasilitas C ++ untuk tipe yang ditentukan pengguna menyediakan solusi alternatif. Sebagai contoh:

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 tampaknya menambahkan struct anonim, sehingga revisi C ++ di masa mendatang dapat menambahkannya.

bames53
sumber
2
+1: Contoh saya bergantung pada perilaku tidak terdefinisi di C ++ - sesuatu yang tidak saya sadari saat saya menulis pertanyaan.
Adrian McCarthy
2
"C ++ tidak mengizinkan Anda untuk menulis ke satu anggota serikat [...] dan kemudian membaca dari anggota lain" - kecuali anggota tersebut adalah objek tata letak standar dan berbagi urutan awal yang sama dari anggota mereka sendiri, dan Anda ' re menulis / membaca mereka anggota dalam kata urutan awal umum. Itu adalah diperbolehkan (yaitu didefinisikan).
underscore_d
5
@underscore_d: Ya, jika tipenya adalah tata letak standar dengan urutan awal yang sama. Namun, struct tidak pernah bisa membuat alias dengan array dengan cara ini, karena aturan "common initial sequence" dari C ++ menyatakan bahwa urutan inisial yang sama hanya dapat berada di antara struct . Array tidak disebutkan, jadi tidak bisa alias seperti ini.
Nicol Bolas
@NicolBolas Oh, haha ​​- percayalah - Saya telah berkali-kali berharap array dan primitif lainnya dimasukkan dalam tunjangan ini! Tapi saya tidak terlalu memikirkan kemungkinan batasan praktisnya, jadi mungkin tidak sesederhana kelihatannya saat ini. Komentar saya lebih umum tetapi mungkin berisiko menyiratkan dengan kelalaian bahwa saya pikir array termasuk dalam ini, jadi terima kasih telah menambahkannya.
underscore_d
"Alasan untuk ini adalah bahwa C mendukung serikat anonim tetapi bukan struct anonim" - Tidak. Catatan kaki Anda menjelaskan bahwa Anda berbicara tentang C99 atau sebelumnya di sini. Istilah "persatuan anonim" tidak muncul di mana pun dalam standar C99. GCC mengklaim dalam diagnosis (dengan opsi -std = c99 -pedantic) bahwa "ISO C99 tidak mendukung struct / unions tanpa nama". Standar tidak menyebutkan apa pun tentang anggota yang tidak disebutkan namanya selain bidang bit yang tidak disebutkan namanya. Saya tidak sepenuhnya yakin apakah deklarasi struct adalah deklarasi, tetapi jika demikian, unions anonim adalah pelanggaran batasan per 6.7p2, paling tidak tidak ditentukan.
21

Saya akan mengatakan, Anda dapat membersihkan vector3deklarasi Anda hanya dengan menggunakanunion

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

Tentu, struktur anonim adalah ekstensi MSVC . Tetapi ISO C11 mengizinkannya sekarang, dan gcc mengizinkannya , dan begitu pula compiler llvm Apple.

Mengapa di C11 dan bukan C ++ 11? Saya tidak yakin, tetapi secara praktis sebagian besar (gcc ++, MSVC ++ dan kompiler C ++ Apple) C ++ mendukung mereka.

bobobobo
sumber
1
1 untuk informasi terbaru. Alasan saya memiliki struct luar adalah karena "kode sebenarnya" memiliki metode juga.
Adrian McCarthy
Satu-satunya hal yang tidak dapat Anda lakukan dengan serikat adalah memiliki anggota data statis, atau menggunakan warisan .
bobobobo
2
Terima kasih. Saya tidak pernah baru serikat dapat digunakan seperti struct atau class.
Adrian McCarthy
Saya tahu Sun studio tidak mendukung struct anonim sebelum C ++ 11 secara default. Jika Anda menulis kode lintas platform dan kompiler tidak diupgrade ke C + 11 maka jangan gunakan struct anonim.
irsis
6

Tidak yakin apa yang kamu maksud. Bagian 9.5 dari spesifikasi C ++, klausul 2:

Sebuah penyatuan bentuk

union { member-specification } ;

disebut serikat anonim; itu mendefinisikan objek tak bernama dari tipe tak bernama.

Anda juga dapat melakukan hal-hal seperti ini:

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

Tidak selalu sangat berguna ... meskipun terkadang berguna dalam definisi makro yang buruk.

Dan
sumber
11
-1 karena ia mengatakan bahwa ia mendefinisikan struct anonim. Lihat komentar di atas pada pertanyaan - Anda mendefinisikan struct tanpa nama, bukan yang anonim.
Johannes Schaub - litb
1

Serikat pekerja bisa jadi anonim; lihat Standar, 9,5 paragraf 2.

Apa tujuan Anda melihat struct atau class anonim memenuhi? Sebelum berspekulasi mengapa ada sesuatu yang tidak ada dalam Standar, saya ingin tahu mengapa itu harus, dan saya tidak melihat penggunaan untuk struct anonim.

David Thornley
sumber
1

Berdasarkan hasil edit, komentar, dan artikel MSDN ini: Struktur Anonim , saya akan menebaknya - ini tidak cocok dengan konsep enkapsulasi. Saya tidak akan mengharapkan anggota kelas untuk mengacaukan namespace kelas saya selain hanya menambahkan satu anggota. Selain itu, perubahan pada struktur anonim dapat memengaruhi kelas saya tanpa izin.

JonM
sumber
1
Karena cara struct / unions anonim dibuat (khusus, sintaks sebaris yang tidak dapat disembunyikan kecuali oleh makro) Anda tidak dapat terkejut bahwa beberapa anggota yang Anda gunakan adalah anggota anonim. Jadi menurut saya alasan ini tidak masuk akal. Alasan sebenarnya adalah bahwa serikat anonim yang didukung dalam C ++, untuk kompatibilitas C saja. C tidak mendukung struct anonim (hingga C11) dan C ++ juga tidak.
bames53
1

Kode Anda

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

seperti

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

yang tentunya tidak valid (di C99 dan sebelumnya).

Alasannya mungkin untuk menyederhanakan penguraian (dalam C), karena dalam hal ini Anda hanya perlu memeriksa bahwa struct / union body hanya memiliki "pernyataan deklarator" seperti

Type field;

Karena itu, gcc dan "kompiler lain" mendukung kolom tanpa nama sebagai ekstensi.

Sunting: Structs anonim sekarang secara resmi didukung di C11 (§6.7.2.1 / 13).

kennytm
sumber
5
Dari perspektif parsing, saya tidak berpikir itu union { ... }berbeda dengan struct { ... }. Yang pertama valid, tetapi yang terakhir tidak.
Johannes Schaub - litb
3
Mengingat betapa sulitnya C ++ untuk diurai secara umum, saya meragukan standar yang berkomitmen untuk struct dan unnamed unnamed tidak diizinkan hanya untuk menyederhanakan penguraian.
Adrian McCarthy
@ Adrian: Saya bilang C, bukan C ++. C ++ mengadopsi sintaks C dan memperluasnya. Mungkin pembuat C ++ tidak melihat kebutuhan untuk mengizinkan anggota struct / union yang tidak disebutkan namanya sehingga mereka tidak mengacaukan bagian sintaks itu.
kennytm
@Adrian, Bagus sekali Adrian, saya selalu tidak berpikir "terlalu sulit untuk diterapkan" akan menjadi perhatian Bjarne dan kru
bobobobo
C dan C ++ keduanya mendukung serikat tanpa nama, jadi komentar yang union { ... };tidak valid salah.
bames53