Apakah standar C secara eksplisit menunjukkan nilai kebenaran sebagai 0 atau 1?

86

Kita tahu bahwa bilangan apa pun yang tidak sama 0dipandang seperti truedi C, jadi kita bisa menulis:

Namun, saya bertanya-tanya apakah benar / salah didefinisikan sebagai 1/ 0dalam C, jadi saya mencoba kode di bawah ini:

Apakah standar C secara eksplisit menunjukkan nilai kebenaran benar dan salah sebagai 1dan 0masing - masing?

Kevin Dong
sumber
3
Saya rasa Pertanyaan SO ini relevan
Imran Ali
3
Saya mencoba menjalankan ini gccdengan -std=c89dan menghasilkan hasil yang sama.
Kevin Dong
1
@Blackhole, dari 15 menjadi 0.
Arturo Torres Sánchez
6
Hampir menipu tetapi lebih dari satu dekade sebelum SO / SE: c-faq.com/bool/bool2.html .
dave_thompson_085
1
Salah itu nol adalah kanon, namun benar umumnya dianggap sebagai "bukan nol". Akan tetapi, programmer menjadi apa adanya, kita semua telah menggunakan 1 sebagai "bukan nol" karena berbagai alasan kita. Anda didorong untuk tidak mempercayai yang benar menjadi persis 1. Meskipun (0 == 0) adalah salah satu contoh Anda, sesuatu seperti (12 == 12) dapat dengan mudah memiliki nilai 12; juga "benar".
Insinyur

Jawaban:

96

Apakah standar C secara eksplisit menunjukkan nilai kebenaran dari truedan falsesebagai 0dan 1masing - masing?

Standar C mendefinisikan true dan falsesebagai makro stdbool.hyang diperluas menjadi 1dan 0masing - masing.

C11-§7.18:

Tiga makro lainnya cocok untuk digunakan dalam #ifarahan pra-pemrosesan. Mereka

yang meluas ke konstanta integer 1,

yang meluas ke konstanta integer 0[...]

Untuk operator ==dan !=, kata standar

C11-§6.5.9 / 3:

Operator ==(sama dengan) dan !=(tidak sama dengan) dianalogikan dengan operator relasional kecuali untuk prioritas yang lebih rendah. 108) Setiap operator menghasilkan 1jika relasi yang ditentukan benar dan 0jika salah. Hasilnya memiliki tipe int. Untuk pasangan operan mana pun, salah satu relasinya benar.

haccks
sumber
20
Bagi saya, pertanyaannya adalah tentang 0 == 0dan 0 != 0lain - lain, bukan nilai makro.
MM
9
Saya pikir ketika dia menulis yang truedia maksud adalah "nilai perbandingan yang benar" atau sesuatu, bukan makrotrue
MM
1
@Tokopedia Ya, draf C99 memiliki paragraf serupa.
haccks
1
@haccks: Anda bisa mengatakannya tanpa ragu-ragu "identik" Saya baru saja menaikkan kutipan Anda karena saya terlalu malas untuk mencari berdasarkan paragraf karena saya merujuk ke c99 bila diperlukan. Dan saya dapat menemukannya hanya dengan mencarinya melalui ctrl+ f;)
dhein
2
@MooingDuck: NaN == NaNsalah dan NaN != NaNbenar. Tidak ada masalah dengan pernyataan itu.
kennytm
51

Ini tidak secara eksplisit ditunjukkan dalam C11. Semua operasi tingkat bahasa akan mengembalikan 1 sebagai benar (dan menerima apa pun yang bukan nol termasuk NaN sebagai benar).

  • Jika Anda mengkhawatirkan _Bool, maka benar harus 1 karena standar hanya mengharuskannya untuk menampung 0 dan 1. (§6.2.5 / 2).
  • Juga di <stdbool.h>makro truemeluas ke 1(§7.18 / 3)
  • ==, !=, <, >, <=Dan>= kembali 0 atau 1 (§6.5.8 / 6, §6.5.9 / 3).
  • !, &&dan|| mengembalikan 0 atau 1 (§6.5.3.3 / 5, §6.5.13 / 3, §6.5.14 / 3)
  • defined meluas ke 0 atau 1 (§6.10.1 / 1)

Tetapi semua fungsi pustaka standar misalnya islowerkatakan saja "bukan nol" untuk kebenaran (misalnya §7.4.1 / 1, §7.17.5.1 / 3, §7.30.2.1 / 1, §7.30.2.2.1 / 4).


§6.2.5 / 2 : Objek yang dideklarasikan sebagai tipe _Boolcukup besar untuk menyimpan nilai 0 dan 1.

§6.5.5.3 / 5 : Hasil dari operator negasi logis !adalah 0 jika nilai operannya tidak sama dengan 0, 1 jika nilai operannya sebanding dengan 0.…

§6.5.8 / 6 : Masing-masing operator <(kurang dari), >(lebih besar dari), <=(kurang dari atau sama dengan), dan >=(lebih besar dari atau sama dengan) akan menghasilkan 1 jika relasi yang ditentukan benar dan 0 jika itu salah. 107) ...

§6.5.9 / 3 : The ==(sama dengan) dan!= (tidak sama dengan) dianalogikan dengan operator relasional kecuali untuk prioritas yang lebih rendah.108) Masing-masing operator menghasilkan 1 jika relasi yang ditentukan benar dan 0 jika benar Salah. …

§6.5.13 / 3 : &&Operator harus menghasilkan 1 jika kedua operannya tidak sama dengan 0; …

§6.5.14 / 3 : ||Operator harus menghasilkan 1 jika salah satu operannya tidak sama dengan 0; …

§6.10.1 / 1 :… ini mungkin berisi ekspresi operator unary dari bentuk - defined identifier- atau - defined ( identifier )- yang bernilai 1 jika…

§7.4.1 (Fungsi klasifikasi karakter) / 1 : Fungsi dalam subpasal ini mengembalikan bukan nol (benar) jika dan hanya jika…

§7.18 / 3 : Tiga makro yang tersisa cocok untuk digunakan dalam #ifarahan pra-pemrosesan . Mereka adalah - true- yang meluas ke konstanta bilangan bulat 1,…

§7.17.5.1 / 3 : Fungsi atomic_is_lock_freegenerik mengembalikan bukan nol (benar) jika dan hanya jika operasi objek bebas kunci. …

§7.30.2.1 (Fungsi klasifikasi karakter luas) / 1 : Fungsi dalam subpasal ini mengembalikan bukan nol (benar) jika dan hanya jika…

§7.30.2.2.1 / 4 : iswctypeFungsi mengembalikan bukan nol (benar) jika dan hanya jika…

kennytm
sumber
23

Ada dua area standar yang perlu Anda waspadai ketika berhadapan dengan nilai Boolean (maksud saya nilai benar / salah daripada bool/_Booltipe C tertentu ) di C.

Yang pertama berkaitan dengan hasil ekspresi dan dapat ditemukan di berbagai bagian C11 6.5 Expressions(operator relasional dan persamaan, misalnya). Intinya adalah, setiap kali nilai Boolean dihasilkan oleh ekspresi, itu ...

... menghasilkan 1 jika relasi yang ditentukan benar dan 0 jika salah. Hasilnya memiliki tipe int.

Jadi, ya, hasil dari ekspresi yang menghasilkan Boolean akan menjadi satu untuk benar, atau nol untuk salah. Ini cocok dengan apa yang akan Anda temukan di stdbool.hmana makro standar truedan falseditentukan dengan cara yang sama.

Namun perlu diingat bahwa, mengikuti prinsip ketahanan "jadilah konservatif dalam apa yang Anda kirim, liberal dalam apa yang Anda terima", interpretasi bilangan bulat dalam konteks Boolean agak lebih santai.

Sekali lagi, dari berbagai bagian 6.5, Anda akan melihat bahasa seperti:

The ||operator harus menghasilkan 1 jika salah satu dari Operand dibandingkan yang tidak sama dengan 0; jika tidak, itu menghasilkan 0. Hasilnya memiliki tipe int.

Dari (dan bagian lain), sudah jelas bahwa nol dianggap palsu dan setiap nilai lain benar.


Selain itu, bahasa yang menentukan nilai apa yang digunakan untuk pembangkitan dan interpretasi Boolean juga muncul kembali di C99 dan C89 sehingga mereka sudah ada cukup lama. Bahkan K&R (ANSI-C edisi kedua dan edisi pertama) menetapkan itu, dengan segmen teks seperti:

Ekspresi relasional seperti i > jdan ekspresi logis yang dihubungkan oleh &&dan ||didefinisikan memiliki nilai 1jika benar, dan 0jika salah.

Di bagian uji if, while, for, dll, "true" hanya berarti "non-nol".

The &&Operator ... mengembalikan 1 jika kedua operan membandingkan tidak sama dengan nol, 0 sebaliknya.

The ||Operator ... mengembalikan 1 jika salah satu operan yang membandingkan tidak sama dengan nol, dan 0 sebaliknya.

Makro stdbool.hmuncul kembali di C99 juga, tetapi tidak di C89 atau K&R karena file header itu tidak ada pada saat itu.

paxdiablo
sumber
2
perhatikan bahwa ||,, dll. ==, !=menghasilkan int, bukan tipe boolean
MM
2
Saya memilih pertanyaan ini untuk pertanyaan yang benar. Bagi saya pertanyaannya juga tentang operator relasional dan bukan makro.
ckruczek
"Pada bagian uji if, while, for, dll, 'true' hanya berarti 'non-nol'." Ini adalah bagian terpenting dari jawabannya dan, menurut saya, merupakan pilihan yang disayangkan dari Dennis Ritchie sejak dulu. Siapapun yang memiliki fungsi tertulis yang mengembalikan kode kesalahan sebagai nilai kembali umumnya memiliki #define noErr 0dan kode kesalahan bukan nol adalah kesalahan. Dan masalahnya adalah kesederhanaan dan keindahan if ( ready_to_do_something() ){do_something();} tidak berhasil. Itu harus if ( !not_ready_to_do_something() ){do_something();}"Ada banyak kebohongan, tapi hanya satu kebenaran." BENAR harus 0.
robert bristow-johnson
Karena penasaran, bagaimana draf pertama aturan C menentukan perilaku "&&" dan "||" dalam kasus di mana operan memiliki nilai selain 0 atau 1? Teks yang Anda kutip mengatakan "ekspresi logis" dihubungkan oleh && dan ||, tetapi bagaimana jika operator tersebut menghubungkan hal-hal selain ekspresi logika?
supercat
1
@denham, ya. Dalam salinan paling awal K&R yang saya miliki (edisi pertama, cetak 14, satu sangat awal yang menyebutkan karakteristik perangkat keras dari empat mesin tipikal, PDP-11, Honeywell-6000, IBM-370 dan Interdata-8/32), A.7.6/7/10/11(relasional / persamaan / logika-dan / logika-atau) semua menentukan bahwa itu memberikan 0 atau 1 sebagai hasil. Telah memperbarui jawaban untuk memasukkan itu.
paxdiablo
10

Anda mencampurkan banyak hal yang berbeda: pernyataan kontrol, operator, dan tipe boolean. Masing-masing memiliki aturannya sendiri.

Pernyataan kontrol berfungsi seperti misalnya ifpernyataan, C11 6.4.8.1:

Dalam kedua bentuk, substatement pertama dijalankan jika ekspresi tidak sama dengan 0.

while, fordll memiliki aturan yang sama. Ini tidak ada hubungannya dengan "benar" atau "salah".

Adapun operator yang seharusnya menghasilkan hasil boolean, mereka sebenarnya menghasilkan intdengan nilai 1 atau 0. Sebagai contoh operator persamaan, C11 6.5.9:

Masing-masing operator menghasilkan 1 jika relasi yang ditentukan benar dan 0 jika salah

Semua hal di atas adalah karena C tidak memiliki tipe boolean sampai tahun 1999, dan bahkan ketika sudah mendapatkannya, aturan di atas tidak berubah. Jadi tidak seperti kebanyakan bahasa pemrograman lain di mana pernyataan dan operator menghasilkan tipe boolean (seperti C ++ dan Java), mereka hanya menghasilkan int, dengan nilai nol atau bukan nol. Misalnya, sizeof(1==1)akan memberikan 4 di C tetapi 1 di C ++.

Tipe boolean sebenarnya di C diberi nama _Booldan membutuhkan kompiler modern. Header stdbool.hmendefinisikan makro bool, truedan false, yang diperluas menjadi _Bool, 1dan 0masing - masing (untuk kompatibilitas dengan C ++).


Namun hal ini dianggap sebagai praktik pemrograman yang baik untuk memperlakukan pernyataan kontrol dan operator seolah-olah mereka benar-benar membutuhkan / menghasilkan tipe boolean. Standar pengkodean tertentu seperti MISRA-C merekomendasikan praktik semacam itu. Itu adalah:

if(ptr == NULL) dari pada if(ptr) .

if((data & mask) != 0) dari pada if(data & mask) .

Tujuan dari gaya tersebut adalah untuk meningkatkan keamanan tipe dengan bantuan alat analisis statis, yang pada gilirannya mengurangi bug. Bisa dibilang, gaya ini hanya bermakna jika Anda memang menggunakan penganalisis statis. Meskipun dalam beberapa kasus, ini mengarah ke kode yang lebih mudah dibaca dan terdokumentasi sendiri, misalnya

Bagus, maksudnya jelas, kodenya mendokumentasikan sendiri.

melawan

Buruk. Bisa berarti apa saja, dan kita harus mencari tipe cuntuk memahami kodenya. Apakah itu bilangan bulat, penunjuk atau karakter?

Lundin
sumber
1
sizeof(bool)adalah implementasi khusus di C ++. Lihat stackoverflow.com/questions/4897844/is-sizeofbool-defined .
David Hammen
@DavidHammen Sama seperti sizeof (0 == 0) juga ditentukan implementasi. Itu hanyalah sebuah contoh.
Lundin
Saya pikir C memang mengubah aturan untuk tipe Boolean. Jenis uintN jenis lain (termasuk banyak jenis "bit" kompiler lama) menyimpan bit N yang lebih rendah dari suatu nilai dan mengabaikan bit yang lebih tinggi, sedangkan jenis Boolean baru secara efektif "atau" bersama-sama semua bit.
supercat
1
Haruskah begitu if(ptr != NULL), atau mungkin if(!ptr)?
Mathieu K.
1
if(c == '\0')cocok untuk kesalahan pengkodean pemula yang sangat umum if(c = '\0'), jadi saya menghindarinya. Setuju, if(c)itu buruk ... mestinya, misalnya,if(valveIsOpen)
aja
4

Saya telah memprogram dalam banyak bahasa. Saya telah melihat true be 1 atau -1 tergantung pada bahasanya. Logika di balik wujud sejati 1 adalah bahwa sedikit adalah 0 atau 1. Logika di balik wujud sejati -1 adalah bahwa! operator adalah pelengkap seseorang. Itu mengubah semua 1 menjadi 0 dan semua 0 menjadi 1 dalam int. Jadi, untuk int,! 0 = -1 dan! (- 1) = 0. Ini telah cukup membuat saya tersandung sehingga saya tidak membandingkan sesuatu menjadi == true, tetapi membandingkannya menjadi! = False. Dengan begitu, gaya pemrograman saya berfungsi di semua bahasa. Jadi jawaban saya adalah jangan khawatir tentang itu, tetapi programlah agar kode Anda berfungsi dengan benar.

Russell Hankins
sumber
bagaimana bisa ! ubah semua 0 menjadi 1 dan tetap menghasilkan 0 untuk! 5?
codeshot
@ Cod Tidak bisa. Tetapi poin yang dia buat adalah bahwa tidak semua bahasa memperlakukan operan dari! sebagai boolean. Beberapa suguhan! sebagai C ~ - yaitu, pelengkap bitwise. Dalam hal ini, menentukan nilai yang dihasilkan membutuhkan mengetahui jenis variabel terlebih dahulu, jadi! (Uint32_t) 5 akan menjadi 4.294.967.290. Tapi! 0 masih 4.294.967.295, dan 4.294.967.295 benar.
Pegasus Epsilon
1

Jawaban ini perlu dilihat lebih dekat.

Definisi sebenarnya di C ++ adalah bahwa apa pun yang bukan 0 akan dianggap benar. Mengapa ini relevan? Karena C ++ tidak tahu apa itu integer dengan cara kita memikirkannya - kita menciptakan makna itu, yang dimilikinya hanyalah shell dan aturan untuk artinya. Ia tahu apa itu bit, yang membentuk sebuah integer.

1 sebagai bilangan bulat direpresentasikan secara longgar dalam bit, katakan int 8-bit ditandatangani sebagai 0000 0001. Seringkali apa yang kita lihat secara visual adalah sedikit kebohongan, -1 adalah cara yang jauh lebih umum untuk merepresentasikannya karena sifatnya yang ditandatangani dari 'integer'. 1 benar-benar tidak bisa berarti benar, mengapa? Karena BUKAN operasinya adalah 1111 1110. Itu masalah yang sangat besar untuk boolean. Ketika kita berbicara tentang boolean, itu hanya 1 bit - sangat sederhana, 0 salah dan 1 benar. Semua operasi logika dianggap sepele. Inilah mengapa '-1' harus ditetapkan sebagai 'true' untuk integer (bertanda tangan). 1111 1111 NOT'ed menjadi 0000 0000 --- logika bertahan dan kami baik-baik saja. Unsigned int sedikit rumit dan lebih umum digunakan di masa lalu - di mana 1 berarti benar karena mudah untuk menyiratkan logika bahwa '

Itulah penjelasannya. Saya mengatakan jawaban yang diterima di sini salah - tidak ada definisi yang jelas dalam definisi C / C ++. Boolean adalah boolean, Anda dapat memperlakukan bilangan bulat sebagai boolean, tetapi fakta bahwa keluarannya adalah bilangan bulat tidak berarti apa pun tentang operasi yang sebenarnya dilakukan adalah bitwise.

Tommy
sumber
4
Pertanyaannya adalah tentang C, bukan C ++.
glglgl
0

Itu terjadi karena Operator Relasional dalam printfpernyataan Anda .

Operator ==dan operator!=

Karena (0 == 0)berlaku demikian, hal itu memberi nilai1

Padahal, (0 != 0)tidak berlaku begitu, memberi nilai 0.

SKD
sumber