Pertanyaan Apakah diperbolehkan untuk enum memiliki nilai yang tidak terdaftar? [duplikat]


Pertanyaan ini sudah memiliki jawaban di sini:

Katakanlah, kami punya

enum E
{
  Foo = 0,
  Bar = 1
};

Sekarang, kami lakukan

enum E v = ( enum E ) 2;

Lalu

switch ( v )
{
  case Foo:
    doFoo();
  break;
  case Bar:
    doBar();
  break;
  default:
    // Is the compiler required to honor this?
    doOther();
  break;
}

Karena switch di atas menangani setiap kemungkinan nilai yang terdaftar dari enum, apakah diperbolehkan untuk kompilator untuk mengoptimalkan jauh default cabang di atas, atau sebaliknya memiliki perilaku yang tidak ditentukan atau tidak terdefinisi dalam kasus nilai enum tidak ada dalam daftar?

Karena saya mengharapkan bahwa perilaku tersebut harus serupa untuk C dan C ++, pertanyaannya adalah tentang kedua bahasa. Namun, jika ada perbedaan antara C dan C ++ untuk kasus itu, akan lebih baik untuk mengetahuinya juga.


32
2017-11-19 19:44


asal


Jawaban:


Situasi C ++

Dalam C ++, setiap enum memiliki tipe integral yang mendasarinya. Ini bisa diperbaiki, jika dijelaskan secara eksplisit (misalnya: enum test2 : long { a,b};) atau int secara default dalam kasus a scoped enum (misalnya: enum class test { a,b };):

7.2 / 5: Setiap enumerasi mendefinisikan tipe yang berbeda dari semua tipe lainnya. Setiap enumerasi juga memiliki tipe yang mendasari. (...) jika tidak   secara eksplisit ditentukan, tipe yang mendasari dari tipe enumerasi scoped   adalah int. Dalam kasus ini, tipe yang mendasari dikatakan diperbaiki.

Dalam kasus sebuah tanpa aliran enum di mana jenis yang mendasari tidak terekam secara pasti (contoh Anda), standar ini memberikan lebih banyak fleksibilitas untuk kompilator Anda:

7.2 / 6: Untuk enumerasi yang tipe dasarnya tidak tetap, tipe yang mendasari adalah tipe integral yang dapat mewakili semua   nilai enumerator yang ditentukan dalam enumerasi. (...) Ini adalah implementasi-didefinisikan yang jenis integral digunakan sebagai yang mendasarinya   ketik kecuali bahwa tipe yang mendasari tidak boleh lebih besar dari int   kecuali jika nilai enumerator tidak bisa masuk dalam int atau unsigned   int.

Sekarang a hal yang sangat rumit: nilai-nilai yang dapat dipegang oleh variabel enum tergantung pada apakah atau tidak jenis yang mendasari adalah tetap:

  • jika itu diperbaiki, "Nilai-nilai dari pencacahan adalah nilai-nilai dari tipe dasar. " 

  • selain itu, ini adalah nilai integral dalam minimum dan maksimum bidang bit terkecil yang dapat menampung enumerator terkecil dan yang terbesar.

Anda berada dalam kasus kedua, meskipun kode Anda akan bekerja pada sebagian besar kompiler, bitfield yang paling kecil memiliki ukuran 1 dan sehingga satu-satunya nilai yang dapat Anda pegang dengan pasti pada semua compiler C ++ compliant adalah antara 0 dan 1 ... Jika Anda ingin memastikan bahwa Anda dapat mengatur nilai 2, Anda harus membuatnya enum scoped, atau secara explicitely menunjukkan tipe yang mendasarinya. 

Lebih banyak membaca:
 

Situasi C

Situasi C jauh lebih sederhana:

6.2.5 / 16: Pencacahan terdiri dari satu set nilai konstanta bilangan bulat yang bernama. Setiap pencacahan yang berbeda merupakan enumerasi yang berbeda   mengetik.

Jadi pada dasarnya, ini adalah int:

6.7.2.2./2 Ekspresi yang mendefinisikan nilai konstanta enumerasi adalah ekspresi konstan integer yang memiliki nilai   representable sebagai int.

Dengan batasan berikut:

Setiap tipe yang disebutkan harus kompatibel dengan char, integer bertanda tangan   ketik, atau jenis integer yang tidak bertanda tangan. Pilihan jenisnya adalah   implementasi-defined, 128) tetapi harus mampu mewakili   nilai dari semua anggota pencacahan.


18
2017-11-19 21:39



Dalam C an enum type adalah tipe integer yang cukup besar untuk menampung semua enum konstanta:

(C11, 6.7.2.2p4) "Setiap jenis yang disebutkan harus kompatibel dengan char, tipe integer bertanda tangan, atau jenis integer unsigned. Pilihan jenis adalah implementasi-didefinisikan, 110) tetapi harus mampu mewakili nilai-nilai semua anggota pencacah ".

Katakanlah jenis yang dipilih untuk enum E aku s _Bool. SEBUAH _Bool objek hanya dapat menyimpan nilai-nilai 0 dan 1. Tidak mungkin memiliki _Bool objek menyimpan nilai yang berbeda dari 0 atau 1 tanpa memunculkan perilaku tidak terdefinisi.

Dalam hal ini compiler diperbolehkan untuk menganggap bahwa objek dari enum E jenis hanya bisa tahan 0 atau 1 dalam program yang benar-benar sesuai dan diizinkan untuk mengoptimalkan keluar default switch case.


3
2017-11-19 20:22



C ++ Std 7.2.7 [dcl.enum]:

Adalah mungkin untuk mendefinisikan suatu pencacahan yang memiliki nilai-nilai yang tidak didefinisikan oleh para enumeratornya.

Jadi, Anda dapat memiliki nilai enumerasi yang tidak terdaftar dalam daftar enumerator.

Namun dalam kasus spesifik Anda, 'tipe yang mendasari' tidak 'tetap' (7.2.5). Spesifikasi tidak mengatakan yang merupakan tipe yang mendasari dalam kasus itu, tetapi harus integral. Karena char adalah jenis yang paling kecil, kita dapat menyimpulkan bahwa ada nilai-nilai lain dari enum yang tidak ditentukan dalam daftar enumerator.

Btw, saya pikir kompilator dapat mengoptimalkan kasus Anda ketika itu dapat menentukan bahwa tidak ada nilai lain yang pernah ditugaskan untuk v, yang aman, tapi saya pikir tidak ada kompiler yang belum pintar.


0
2017-11-19 20:08



Juga, 7.2 / 10:

Ekspresi tipe aritmatika atau enumerasi dapat dikonversi menjadi   tipe enumerasi secara eksplisit. Nilai tidak berubah jika berada di   kisaran nilai pencacahan dari tipe pencacahan; sebaliknya   nilai enumerasi yang dihasilkan tidak ditentukan.


0
2017-11-19 20:16



Di C enumerator ada tipe int  . Dengan demikian, setiap nilai integer dapat ditetapkan ke objek dari tipe enumerasi.

Dari Standar C (6.7.2.2 penentu Enumerasi)

3 Pengidentifikasi dalam daftar enumerator dinyatakan sebagai konstanta itu   memiliki tipe int dan dapat muncul di mana saja seperti diizinkan.

Di C ++ enumerator memiliki tipe enumerasi yang mendefinisikannya. Dalam C ++ Anda sebaiknya secara eksplisit menentukan tipe underlaying atau compiler menghitung sendiri nilai maksimum yang diizinkan.

Dari Standar C ++ (7,2 deklarasi Enumerasi)

5 Setiap pencacahan menentukan jenis yang berbeda dari semua jenis lainnya. Setiap enumerasi juga memiliki tipe yang mendasari. Tipe yang mendasari dapat secara eksplisit ditentukan menggunakan enum-base; jika tidak secara eksplisit ditentukan, tipe yang mendasari dari tipe enumerasi scoped adalah int. Dalam kasus ini, tipe yang mendasari dikatakan diperbaiki. Mengikuti tanda kurung kurung dari enum-specifier, setiap pencacah memiliki tipe enumerasinya.

Jadi dalam C nilai yang mungkin dari enum adalah nilai integer. Compiler mungkin tidak mengoptimalkan switch yang menghapus label default.


-1
2017-11-19 19:55



Di C dan C ++, ini bisa berfungsi.

Kode yang sama untuk keduanya:

#include <stdio.h>

enum E
{
  Foo = 0,
  Bar = 1
};

int main()
{
    enum E v = (enum E)2;    // the cast is required for C++, but not for C
    printf("v = %d\n", v);
    switch (v) {
    case Foo:
        printf("got foo\n");
        break;
    case Bar:
        printf("got bar\n");
        break;
    default:
        printf("got \n", v);
        break;
    }
}

Output yang sama untuk keduanya:

v = 2
got default

Di C, sebuah enum adalah tipe integral, sehingga Anda dapat menetapkan nilai integer ke dalamnya tanpa mentransmisi. Dalam C ++, sebuah enum adalah tipenya sendiri.


-1
2017-11-19 19:56