Cetak teks sebagai ganti nilai dari C enum

89
avi
sumber
Keluaran yang Anda harapkan adalah mencetak string "Sunday", dll.?
GalacticCowboy

Jawaban:

104

Pencacahan dalam C adalah angka yang memiliki nama yang sesuai di dalam kode Anda. Mereka bukan string, dan nama yang diberikan padanya di kode sumber tidak dikompilasi ke dalam program Anda, sehingga tidak dapat diakses pada waktu proses.

Satu-satunya cara untuk mendapatkan yang Anda inginkan adalah menulis sendiri fungsi yang menerjemahkan nilai pencacahan menjadi string. Misalnya (dengan asumsi di sini bahwa Anda memindahkan deklarasi di enum Daysluar main):

Alternatifnya, Anda bisa menggunakan larik sebagai peta, mis

Tetapi di sini Anda mungkin ingin menetapkan Sunday = 0dalam pencacahan agar aman ... Saya tidak yakin apakah standar C mengharuskan kompiler untuk memulai pencacahan dari 0, meskipun sebagian besar melakukannya (saya yakin seseorang akan berkomentar untuk mengkonfirmasi atau menyangkal ini ).

Tyler McHenry
sumber
3
Ah, Anda mengalahkan saya untuk solusi array. : P Tapi ya, enum selalu dimulai dari 0 kecuali Anda menentukan nilai yang berbeda.
casablanca
1
Jika saya mengandalkan penggunaan pencacahan sebagai indeks, saya sebenarnya lebih suka memberi nomor secara eksplisit masing-masing. Tidak perlu menurut standar, tetapi sebagai penyusun grup belum sepenuhnya menjadi yang terbaik dalam mengikuti standar menurut pengalaman saya.
jdmichal
3
Standar C mengatakan, "Jika pencacah pertama tidak memiliki =, nilai konstanta pencacahannya adalah 0". Tapi tidak ada salahnya untuk membuatnya eksplisit.
Michael Burr
17
Jangan lupa bahwa dengan C99 Anda bisa melakukannya const char* dayNames[] = {[Sunday] = "Sunday", [Monday] = "Monday", [Tuesday] = "Tuesday", /* ... etc ... */ };. Anda tahu, jika hari-hari dalam seminggu diatur ulang, atau Anda memutuskan bahwa Senin adalah hari pertama dalam seminggu.
Tim Schaeffer
2
@ user3467349 Itu (perangkaian preprocessor) hanya mengubah simbol setelah # menjadi string. Jadi, ya, #Monday akan berubah menjadi "Monday" tetapi Days TheDay = Monday; printf("%s", #TheDay);akan mencetak "TheDay".
Tyler McHenry
29

Saya menggunakan sesuatu seperti ini:

dalam file "EnumToString.h":

lalu di file header apa pun Anda membuat deklarasi enum, hari enum.h

lalu di file bernama EnumToString.c:

lalu di main.c:

ini akan menghasilkan "secara otomatis" string untuk setiap enum yang dideklarasikan dengan cara ini dan termasuk dalam "EnumToString.c"

Vargas
sumber
4
Ini jelek untuk dibaca, tetapi Anda tidak memiliki duplikasi data. (Tidak seperti orang lain.) Aku ragu apakah akan menyukai ini.
Kim Reece
1
1 untuk solusi kreatif yang luar biasa tanpa duplikasi data dan mungkin pemeliharaan / fleksibilitas terbaik, tapi ya! Saya rasa saya masih lebih suka menggunakan rute const char * [].
terwujud
4
Ya, perawatannya luar biasa! Sangat mudah untuk memperbarui ketika hari dalam seminggu berubah! </sarcasm> Ngomong-ngomong, ini bahkan tidak berguna untuk tujuan pelokalan karena pemetaan antara string bahasa Inggris dan nama dalam program sekarang sudah di-hardcode oleh upaya Anda untuk menghindari duplikasi. Setidaknya dengan pendekatan lain, dimungkinkan untuk menerjemahkan string tanpa mengubah setiap kejadian di file sumber.
R .. GitHub STOP HELPING ICE
1
Anda mungkin dapat menginternasionalkannya dengan (dengan sesuatu seperti gettext) mengubah pernyataan return menjadi return _(#element)dan sejenisnya.
Vargas
Ketika C preprocessor berguna tapi ini jelek, saya biasanya menggantinya dengan generator kode sederhana atau preprocessor kustom dalam bahasa scripting. Dan faktanya, saya memiliki skrip Python yang saya gunakan untuk tujuan ini di banyak proyek. Tapi saya tidak sering menggunakannya saat ini — untuk banyak kasus penggunaan Anda bisa lolos hanya dengan menggunakan string dan tidak mengganggu enum (dan terlebih lagi di C ++ atau ObjC).
abarnert
7

Cara saya biasanya melakukan ini adalah dengan menyimpan representasi string dalam array terpisah dalam urutan yang sama, kemudian mengindeks array dengan nilai enum:

casablanca
sumber
4

enums di C tidak benar-benar berfungsi seperti yang Anda harapkan. Anda dapat menganggapnya seperti konstanta yang dimuliakan (dengan beberapa manfaat tambahan terkait menjadi sebuah koleksi konstanta semacam itu), dan teks yang Anda tulis untuk "Minggu" benar-benar diselesaikan menjadi angka selama kompilasi, teks tersebut akhirnya dibuang.

Singkatnya: untuk melakukan apa yang benar-benar Anda inginkan, Anda harus menyimpan array string atau membuat fungsi untuk memetakan dari nilai enum ke teks yang ingin Anda cetak.

Mark Elliot
sumber
4

Pencacahan dalam C pada dasarnya adalah gula sintaksis untuk daftar nama dari nilai integer yang diurutkan secara otomatis. Artinya, bila Anda memiliki kode ini:

Kompiler Anda benar-benar mengeluarkan ini:

Oleh karena itu, mengeluarkan enumerasi C sebagai string bukanlah operasi yang masuk akal bagi kompilator. Jika Anda ingin memiliki string yang dapat dibaca manusia untuk ini, Anda perlu menentukan fungsi untuk mengubah dari enumerasi menjadi string.

jdmichal.dll
sumber
4

Berikut cara yang lebih bersih untuk melakukannya dengan makro:

Saya tidak yakin apakah ini benar-benar praprosesor b / w portabel, tetapi berfungsi dengan gcc.

Ini adalah c99 btw, jadi gunakan c99 strictjika Anda menghubungkannya ke (kompiler online) ideone .

Tim Schaeffer
sumber
Harus menyukai betapa makro “bersih” itu :-).
mk12
3

Saya tahu saya terlambat ke pesta, tapi bagaimana dengan ini?

Dengan cara ini, Anda tidak perlu menyinkronkan array enumdan secara manual char*. Jika Anda seperti saya, kemungkinan besar nanti Anda akan mengubah enum, danchar* array akan mencetak string yang tidak valid. Ini mungkin bukan fitur yang didukung secara universal. Tapi afaik, sebagian besar kompiler hari mordern C mendukung gaya penginisialisasi yang ditunjuk ini.

Anda dapat membaca lebih lanjut tentang penginisialisasi yang ditentukan di sini .

empat puluh dua
sumber
1

Pertanyaannya adalah Anda ingin menulis nama hanya satu kali.
Saya punya ider seperti ini:

#define __ENUM(situation,num) \
    int situation = num;        const char * __##situation##_name = #situation;

    const struct {
        __ENUM(get_other_string, -203);//using a __ENUM Mirco make it ease to write, 
        __ENUM(get_negative_to_unsigned, -204);
        __ENUM(overflow,-205);
//The following two line showing the expanding for __ENUM
        int get_no_num = -201;      const char * __get_no_num_name = "get_no_num";
        int get_float_to_int = -202;        const char * get_float_to_int_name = "float_to_int_name";

    }eRevJson;
#undef __ENUM
    struct sIntCharPtr { int value; const char * p_name; };
//This function transform it to string.
    inline const char * enumRevJsonGetString(int num) {
        sIntCharPtr * ptr = (sIntCharPtr *)(&eRevJson);
        for (int i = 0;i < sizeof(eRevJson) / sizeof(sIntCharPtr);i++) {
            if (ptr[i].value == num) {
                return ptr[i].p_name;
            }
        }
        return "bad_enum_value";
    }

ia menggunakan struct untuk memasukkan enum, sehingga printer ke string dapat mengikuti setiap nilai enum yang ditentukan.

int main(int argc, char *argv[]) {  
    int enum_test = eRevJson.get_other_string;
    printf("error is %s, number is %d\n", enumRevJsonGetString(enum_test), enum_test);

>error is get_other_string, number is -203

Perbedaan dengan enum adalah pembangun tidak dapat melaporkan kesalahan jika nomor diulang. Jika Anda tidak suka menulis nomor, __LINE__bisa menggantinya:

#define ____LINE__ __LINE__
#define __ENUM(situation) \
    int situation = (____LINE__ - __BASELINE -2);       const char * __##situation##_name = #situation;
constexpr int __BASELINE = __LINE__;
constexpr struct {
    __ENUM(Sunday);
    __ENUM(Monday);
    __ENUM(Tuesday);
    __ENUM(Wednesday);
    __ENUM(Thursday);
    __ENUM(Friday);
    __ENUM(Saturday);
}eDays;
#undef __ENUM
inline const char * enumDaysGetString(int num) {
    sIntCharPtr * ptr = (sIntCharPtr *)(&eDays);
    for (int i = 0;i < sizeof(eDays) / sizeof(sIntCharPtr);i++) {
        if (ptr[i].value == num) {
            return ptr[i].p_name;
        }
    }
    return "bad_enum_value";
}
int main(int argc, char *argv[]) {  
    int d = eDays.Wednesday;
    printf("day %s, number is %d\n", enumDaysGetString(d), d);
    d = 1;
    printf("day %s, number is %d\n", enumDaysGetString(d), d);
}

>day Wednesday, number is 3 >day Monday, number is 1

pengguna8931844
sumber
0

Saya baru dalam hal ini tetapi pernyataan switch pasti akan berfungsi

Suraj K Thomas
sumber
Format yang tepat (baca: lekukan) harus menjadi suatu keharusan untuk kode kata demi kata dalam jawaban ...
p4010
0

Saya suka ini memiliki enum di dayNames. Untuk mengurangi pengetikan, kita bisa melakukan hal berikut:

Heng lou
sumber
0

Ada solusi lain: Buat kelas enumerasi dinamis Anda sendiri. Berarti Anda memiliki structfungsi dan beberapa untuk membuat enumerasi baru, yang menyimpan elemen dalam a structdan setiap elemen memiliki string untuk namanya. Anda juga memerlukan beberapa tipe untuk menyimpan elemen individual, fungsi untuk membandingkannya dan sebagainya. Berikut ini contohnya:

Seharusnya fungsi enumerasi ada di unit terjemahannya masing-masing, tapi di sini saya gabungkan supaya lebih sederhana.

Keuntungannya adalah solusi ini fleksibel, mengikuti prinsip KERING, Anda dapat menyimpan informasi bersama dengan setiap elemen, Anda dapat membuat enumerasi baru selama runtime dan Anda dapat menambahkan elemen baru selama runtime. Kerugiannya adalah ini kompleks, membutuhkan alokasi memori dinamis, tidak dapat digunakan dalam switch- case, membutuhkan lebih banyak memori dan lebih lambat. Pertanyaannya adalah jika Anda tidak boleh menggunakan bahasa tingkat yang lebih tinggi dalam kasus di mana Anda membutuhkannya.

12431234123412341234123
sumber
-3

TheDay memetakan kembali ke beberapa tipe integer. Begitu:

Mencoba mengurai TheDay sebagai string, dan akan mencetak sampah atau macet.

printf tidak aman untuk mengetik dan memercayai Anda untuk memberikan nilai yang tepat. Untuk mencetak nama nilainya, Anda perlu membuat beberapa metode untuk memetakan nilai enum ke string - baik tabel pencarian, pernyataan sakelar raksasa, dll.

Michael
sumber