Mengapa "sizeof (a? True: false)" memberikan output empat byte?

133

Saya punya sedikit kode tentang sizeofoperator dengan operator ternary:

#include <stdio.h>
#include <stdbool.h>

int main()
{
    bool a = true;
    printf("%zu\n", sizeof(bool));  // Ok
    printf("%zu\n", sizeof(a));     // Ok
    printf("%zu\n", sizeof(a ? true : false)); // Why 4?
    return 0;
}

Output ( GCC ):

1
1
4 // Why 4?

Tapi di sini,

printf("%zu\n", sizeof(a ? true : false)); // Why 4?

booleanjenis pengembalian operator ternary dan booljenis sizeof adalah 1byte dalam C.

Lalu mengapa sizeof(a ? true : false)memberikan output empat byte?

msc
sumber
39
sizeof(true)dan sizeof(false)juga 4: ide.geeksforgeeks.org/O5jvuN
tkausl
7
Pertanyaan yang lebih menarik di sini adalah mengapa implementasi ini "tidak konsisten" karena ia jelas _Boolmemiliki ukuran 1, tetapi tidak truedan false. Tapi standarnya tidak ada yang bisa dikatakan tentang itu sejauh yang saya tahu.
12
@FelixPalmen alasan yang sama mengapa diberikan char a; sizeof(a) == 1dan sizeof('a') == sizeof(int)(dalam C). Ini bukan tentang implementasinya, ini tentang bahasa.
n. 'kata ganti' m.
10
Sudahkah Anda mencoba mencetak sizeof(true)? mungkin itu akan membuat tipis sedikit lebih jelas (khususnya, akan menjadi jelas bahwa operator ternary adalah herring merah).
n. 'kata ganti' m.
4
@ Feliksmen trueadalah #defined menjadi 1 oleh stdbool.hjadi ya, ini adalah definisi literal.
n. 'kata ganti' m.

Jawaban:

223

Itu karena kamu punya #include <stdbool.h>. Header itu mendefinisikan makro true dan falsemenjadi 1dan 0, jadi pernyataan Anda terlihat seperti ini:

printf("%zu\n", sizeof(a ? 1 : 0)); // Why 4?

sizeof(int) adalah 4 di platform Anda.

Justin
sumber
21
"Itu karena kamu memiliki #include <stdbool.h>" Tidak, tidak. sizeof(a ? (uint8_t)1 : (uint8_t)0);akan juga memberikan hasil 4. Promosi bilangan bulat dari ?:operan adalah bagian penting di sini, bukan ukuran truedan false.
Lundin
9
@Lundin: Keduanya penting. Seperti yang ditulis, tipe ini sudah inttanpa promosi. Alasan Anda tidak dapat "memperbaiki" itu adalah promosi default.
R .. GitHub BERHENTI MEMBANTU ICE
5
@PeterSchneider Ini bukan C ++. Ini adalah C. Dalam C ++, truedan falseyang tidak macro; mereka adalah kata kunci. Mereka tidak didefinisikan sebagai 1dan 0, tetapi menjadi nilai benar dan salah dari booltipe.
Justin
5
@PeterSchneider Tidak, Anda belajar sesuatu tentang C hari ini. Jangan membingungkan kedua bahasa. Dalam C ++, sizeof(true)adalah 1. demo .
Rakete1111
1
Benar, campur aduk. Belum membaca dengan cermat dan disesatkan oleh cppreference-link. Kesalahan saya, terima kasih. Tapi bagaimanapun juga saya punya perasaan tentang c ++.
Peter Schneider
66

Di sini, booleantipe pengembalian operator ternary ,

OK, masih ada lagi!

Dalam C, hasil operasi ternary ini adalah tipe int. [catatan di bawah (1,2)]

Karenanya hasilnya sama dengan ekspresi sizeof(int), di platform Anda.


Catatan 1: Mengutip C11, bab §7.18,Boolean type and values <stdbool.h>

[....] Tiga makro sisanya cocok untuk digunakan dalam #ifarahan preprocessing. Mereka

true

yang mengembang ke konstanta integer 1,

false

yang mengembang ke konstanta integer 0, [....]

Catatan 2: Untuk operator bersyarat, bab §6.5.15, ( penekanan pada tambang )

Operan pertama dievaluasi; ada titik urutan antara evaluasinya dan evaluasi operan kedua atau ketiga (mana yang dievaluasi). Operan kedua dievaluasi hanya jika yang pertama membandingkan tidak sama dengan 0; operan ketiga dievaluasi hanya jika yang pertama sebanding dengan 0; hasilnya adalah nilai operan kedua atau ketiga (mana yang dievaluasi), [...]

dan

Jika kedua operan kedua dan ketiga memiliki tipe aritmatika, tipe hasil yang akan ditentukan oleh konversi aritmatika yang biasa, jika diterapkan pada kedua operan tersebut, adalah jenis hasilnya. [....]

karenanya, hasilnya akan bertipe integer dan karena rentang nilai, konstanta-konstanta tersebut adalah tipe int.

Yang mengatakan, saran umum, int main()harus lebih baik int main (void)untuk benar-benar sesuai standar.

Sourav Ghosh
sumber
@ user694733 umm..mengapa tidak? <stdbool.h>mendefinisikan MACROS sebagai tipe int.. apakah itu salah?
Sourav Ghosh
@ BasileStarynkevitch OK, saya melihat sekarang, ini tampaknya memang salah, diperbarui sekarang.
Sourav Ghosh
58

Operator ternary adalah herring merah.

    printf("%zu\n", sizeof(true));

mencetak 4 (atau apa pun yang sizeof(int)ada di platform Anda).

Diasumsikan boolsebagai sinonim untuk charatau tipe serupa dari ukuran 1, dan intlebih besar dari char.

Alasan mengapa sizeof(true) != sizeof(bool)dan sizeof(true) == sizeof(int)hanya karena trueadalah tidak ekspresi tipe bool. Itu ekspresi tipe int. Itu #defined seperti 1dalam stdbool.h.

Tidak ada nilai tipe boolC sama sekali. Setiap nilai tersebut segera dipromosikan int, bahkan ketika digunakan sebagai argumen sizeof. Sunting: paragraf ini tidak benar, argumen untuk sizeoftidak dipromosikan int. Ini tidak memengaruhi kesimpulan apa pun.

n. 'kata ganti' m.
sumber
Jawaban bagus. Setelah saya membaca jawaban yang paling banyak dipilih saat ini, saya berpikir semua pernyataan harus dievaluasi menjadi 4. Ini beres. +1
Pedro A
5
Bukan (bool)1nilai jenis bool?
Ben Voigt
printf("%u\n", sizeof((char) 1));mencetak 1pada platform saya sedangkan printf("%u\n", sizeof(1));cetak 4. Bukankah ini berarti pernyataan Anda "Setiap nilai seperti itu segera dipromosikan ke int, bahkan ketika digunakan sebagai argumen untuk sizeof" adalah salah?
JonatanE
Ini tidak benar-benar menjawab pertanyaan. Ukuran dan jenis truedll tidak terlalu penting dalam hal ?:karena mendapat bilangan bulat dipromosikan ke intbagaimanapun. Yaitu, jawabannya harus menjawab mengapa ?: ikan haring merah.
Lundin
6
Saya pikir jawabannya mengatasi masalah dengan cara terbaik. Anda dipersilakan untuk downvote atau memperbaikinya.
n. 'kata ganti' m.
31

Mengenai jenis boolean di C

Tipe boolean diperkenalkan cukup terlambat dalam bahasa C, pada tahun 1999. Sebelum itu, C tidak memiliki tipe boolean tetapi sebaliknya digunakan intuntuk semua ekspresi boolean. Oleh karena itu semua operator logis seperti > == !dll mengembalikan intnilai 1atau 0.

Itu adalah kebiasaan untuk aplikasi untuk menggunakan jenis buatan seperti typedef enum { FALSE, TRUE } BOOL;, yang juga bermuara pada intjenis -sized.

C ++ memiliki tipe boolean yang jauh lebih baik, dan eksplisit bool, yang tidak lebih besar dari 1 byte. Sedangkan tipe atau ekspresi boolean dalam C akan berakhir sebagai 4 byte dalam kasus terburuk. Beberapa cara kompatibilitas dengan C ++ diperkenalkan di C dengan standar C99. C kemudian mendapat tipe boolean _Booldan juga header stdbool.h.

stdbool.hmenyediakan beberapa kompatibilitas dengan C ++. Header ini mendefinisikan makro bool(ejaan yang sama dengan kata kunci C ++) yang diperluas ke _Bool, tipe yang merupakan tipe integer kecil, kemungkinan besar 1 byte. Demikian pula, tajuk menyediakan dua makro truedan false, ejaan yang sama dengan kata kunci C ++, tetapi dengan kompatibilitas ke belakang untuk program C yang lebih tua . Oleh karena itu truedan falseberkembang ke 1dan 0di C dan tipenya int. Makro ini sebenarnya bukan tipe boolean seperti kata kunci C ++ yang sesuai.

Demikian pula, untuk tujuan kompatibilitas ke belakang, operator logis di C masih kembali intke hari ini, meskipun C saat ini mendapat tipe boolean. Sementara di C ++, operator logis mengembalikan a bool. Dengan demikian ekspresi seperti sizeof(a == b)akan memberikan ukuran intdalam C, tetapi ukuran dari booldalam C ++.

Mengenai operator bersyarat ?:

Operator bersyarat ?:adalah operator aneh dengan beberapa keanehan. Ini adalah kesalahan umum untuk percaya bahwa itu 100% setara dengan if() { } else {}. Tidak terlalu.

Ada titik urutan antara evaluasi operan 1 dan 2 atau 3. The ?:Operator dijamin hanya mengevaluasi baik 2 atau operan-3, sehingga tidak dapat menjalankan efek samping dari operan yang tidak dievaluasi. Kode suka true? func1() : func2()tidak akan dieksekusi func2(). Sejauh ini baik.

Namun , ada aturan khusus yang menyatakan bahwa operan ke-2 dan ke-3 harus secara implisit dipromosikan dan diseimbangkan satu sama lain dengan konversi aritmatika yang biasa . ( Aturan promosi tipe implisit dalam C dijelaskan di sini ). Ini berarti bahwa operan ke-2 atau ke-3 akan selalu setidaknya sebesar int.

Jadi tidak masalah itu truedan falsekebetulan mengetikkan intC karena ungkapan itu akan selalu memberikan setidaknya ukuran suatu intmasalah.

Bahkan jika Anda akan menulis ulang ekspresi itu masih akan mengembalikan ukuran sebuah !sizeof(a ? (bool)true : (bool)false) int

Ini karena jenis promosi implisit melalui konversi aritmatika yang biasa.

Lundin
sumber
1
C ++ sebenarnya tidak menjamin sizeof(bool)==1.
aschepler
1
@aschepler Tidak, tetapi dunia nyata di luar standar C ++ tidak menjaminnya. Sebutkan satu kompiler yang bukan 1.
Lundin
Hai. Saya pikir jawaban ini akan lebih baik tanpa bagian pertama. Bagian kedua menjawab pertanyaan itu. Sisanya, meski menarik, hanyalah kebisingan.
YSC
@YSC Ini awalnya ditandai C dan C ++ keduanya, jadi perbandingan antara jenis bool yang berbeda dan sejarah di belakang mereka diperlukan. Saya ragu saya akan menulis bagian pertama jika bukan karena tag C ++. Namun, kita harus mengerti mengapa sizeof (bool) adalah 1 tetapi sizeof (false) adalah 4 dalam C.
Lundin
21

Jawaban cepat:

  • sizeof(a ? true : false)mengevaluasi ke 4karena truedan falsedidefinisikan <stdbool.h>sebagai 1dan 0masing - masing, sehingga ekspresi memperluas sizeof(a ? 1 : 0)yang merupakan ekspresi integer dengan tipe int, yang menempati 4 byte pada platform Anda. Untuk alasan yang sama,sizeof(true) juga akan mengevaluasi 4pada sistem Anda.

Perhatikan bahwa:

  • sizeof(a ? a : a)juga dievaluasi 4karena operator ternary melakukan promosi integer pada operan kedua dan ketiga jika ini adalah ekspresi integer. Hal yang sama tentu saja terjadi untuk sizeof(a ? true : false)dan sizeof(a ? (bool)true : (bool)false), tetapi menampilkan seluruh ekspresi sebagaibool berperilaku seperti yang diharapkan: sizeof((bool)(a ? true : false)) -> 1.

  • juga perhatikan bahwa operator perbandingan mengevaluasi nilai boolean 1atau0 , tetapi memiliki inttipe: sizeof(a == a) -> 4.

Satu-satunya operator yang menjaga sifat boolean a adalah:

  • operator koma: keduanya sizeof(a, a)dansizeof(true, a) mengevaluasi pada 1saat kompilasi.

  • operator penugasan: keduanya sizeof(a = a)dansizeof(a = true) memiliki nilai 1.

  • operator kenaikan: sizeof(a++) -> 1

Akhirnya, semua hal di atas hanya berlaku untuk C: C ++ memiliki semantik yang berbeda mengenai booltipe, nilai boolean truedan false, operator perbandingan dan operator ternary: semua sizeof()ekspresi ini dievaluasi 1dalam C ++.

chqrlie
sumber
2
Jawaban bagus yang sebenarnya menunjukkan bahwa tidak masalah apa pun jenis truedan keberadaannya false, karena ?:operan akan dipromosikan menjadi bilangan bulat int. Dengan demikian sizeof(a ? (uint8_t)true : (uint8_t)false)juga akan menghasilkan 4 sebagai hasilnya.
Lundin
Jawaban ini mencakup poin penting utama, nilai dipromosikan keint
Chinni
1

Berikut ini cuplikan dari mana yang termasuk dalam sumber

#ifndef __cplusplus

#define bool    _Bool
#define true    1
#define false   0

#else /* __cplusplus */

Ada makro truedan falsedinyatakan sebagai 1 dan 0 masing-masing.

Namun dalam hal ini jenisnya adalah jenis konstanta literal. Baik 0 dan 1 adalah konstanta integer yang sesuai dengan int, sehingga tipenya adalah int.

dan sizeof(int)dalam kasus Anda adalah 4.

u__
sumber
-3

Tidak ada tipe data boolean di C, sebaliknya ekspresi logis mengevaluasi nilai integer 1ketika benar sebaliknya 0.

Ekspresi kondisional seperti if, for, while, atau c ? a : bmengharapkan integer, jika nomor tersebut adalah non-nol itu dianggap truekecuali untuk beberapa kasus khusus, berikut adalah rekursif sum fungsi di mana terner operator akan mengevaluasi truesampai njangkauan 0.

int sum (int n) { return n ? n+sum(n-1) : n ;

Itu juga dapat digunakan untuk NULLmemeriksa sebuah pointer, inilah fungsi rekursif yang mencetak konten dari Singly-Linked-List.

void print(sll * n){ printf("%d -> ",n->val); if(n->next)print(n->next); }
Khaled.K
sumber