Menggunakan nilai boolean di C

Jawaban:

1049

Dari yang terbaik menjadi lebih buruk:

Opsi 1 (C99)

#include <stdbool.h>

pilihan 2

typedef enum { false, true } bool;

Opsi 3

typedef int bool;
enum { false, true };

Opsi 4

typedef int bool;
#define true 1
#define false 0

Penjelasan

  • Opsi 1 hanya akan berfungsi jika Anda menggunakan C99 dan itu adalah "cara standar" untuk melakukannya. Pilih ini jika memungkinkan.
  • Opsi 2, 3 dan 4 dalam praktiknya memiliki perilaku yang sama. # 2 dan # 3 tidak menggunakan #defines, yang menurut saya lebih baik.

Jika Anda ragu-ragu, lanjutkan dengan # 1!

Thomas Bonini
sumber
1
Bisakah Anda menguraikan mengapa mereka adalah yang terbaik untuk pilihan terburuk?
Endolith
1
@ endolith Penjajaran, optimisasi dan cara untuk menyimpan <stdbool.h> boolkompiler yang dipilih mungkin lebih cocok untuk tujuan yang diinginkan dari nilai boolean daripada menggunakan int(yaitu kompiler dapat memilih untuk mengimplementasikan yang boolberbeda dari pada int). Mungkin juga menghasilkan pengecekan tipe yang lebih ketat pada waktu kompilasi, jika Anda beruntung.
blubberdiblub
1
Kenapa digunakan intuntuk bool? Itu sia-sia. Gunakan unsigned char. Atau menggunakan C builtin _Bool.
user12211554
@NoBody Menggunakan tipe yang lebih kecil dapat menghemat memori, tetapi mungkin tidak membuatnya lebih cepat. Seringkali, lebih cepat menggunakan ukuran kata asli prosesor alih-alih ukuran yang lebih kecil karena dapat memerlukan kompiler untuk membuat sedikit pergeseran untuk menyelaraskannya dengan benar
Ted Klein Bergman
241

Beberapa pemikiran tentang boolean di C:

Saya cukup tua sehingga saya hanya menggunakan ints polos sebagai tipe boolean saya tanpa typedefs atau definisi khusus atau enums untuk nilai benar / salah. Jika Anda mengikuti saran saya di bawah ini untuk tidak pernah membandingkan terhadap konstanta boolean, maka Anda hanya perlu menggunakan 0/1 untuk menginisialisasi flag. Namun, pendekatan semacam itu mungkin dianggap terlalu reaksioner di zaman modern ini. Dalam hal ini, seseorang harus menggunakan <stdbool.h>karena setidaknya memiliki manfaat standar.

Apa pun yang disebut konstanta boolean, gunakan hanya untuk inisialisasi. Jangan pernah menulis sesuatu seperti itu

if (ready == TRUE) ...
while (empty == FALSE) ...

Ini selalu bisa diganti dengan yang lebih jelas

if (ready) ...
while (!empty) ...

Perhatikan bahwa ini sebenarnya dapat secara wajar dan dimengerti dibaca dengan keras.

Beri nama positif variabel boolean Anda, yaitu fullsebagai ganti notfull. Yang terakhir mengarah ke kode yang sulit dibaca dengan mudah. Membandingkan

if (full) ...
if (!full) ...

dengan

if (!notfull) ...
if (notfull) ...

Kedua mantan pasangan membaca secara alami, sementara !notfullcanggung membaca bahkan seperti apa adanya, dan menjadi jauh lebih buruk dalam ekspresi boolean yang lebih kompleks.

Argumen Boolean umumnya harus dihindari. Pertimbangkan fungsi yang didefinisikan seperti ini

void foo(bool option) { ... }

Dalam tubuh fungsi, sangat jelas apa artinya argumen karena memiliki nama yang nyaman, dan mudah-mudahan bermakna. Tapi, situs panggilan terlihat seperti

foo(TRUE);
foo(FALSE):

Di sini, pada dasarnya tidak mungkin untuk mengatakan apa arti parameter tanpa selalu melihat definisi fungsi atau deklarasi, dan akan menjadi lebih buruk segera jika Anda menambahkan lebih banyak parameter boolean. Saya sarankan juga

typedef enum { OPT_ON, OPT_OFF } foo_option;
void foo(foo_option option);

atau

#define OPT_ON true
#define OPT_OFF false
void foo(bool option) { ... }

Dalam kedua kasus, situs panggilan sekarang terlihat seperti

foo(OPT_ON);
foo(OPT_OFF);

dimana pembaca setidaknya memiliki kesempatan untuk memahami tanpa mengeruk definisi foo.

Dale Hagglund
sumber
1
Dan bagaimana Anda membandingkan dua variabel untuk kesetaraan? Jangan pernah menggunakan konstanta boolean bekerja dengan baik, tetapi itu tidak menyelesaikan masalah ketika membandingkan dengan yang tidak konstan.
Baruch
Maafkan saya, tapi saya tidak mengerti pertanyaannya. Apakah Anda bertanya bagaimana saya membandingkan dua variabel boolean untuk kesetaraan? Jika demikian, tidak a == bberhasil?
Dale Hagglund
5
@ Kenji Apa yang Anda katakan itu benar, meskipun saya percaya bahwa menggunakan nilai selain yang setara dengan benar hampir selalu merupakan ide yang buruk. Jadi, dalam contoh Anda, dengan asumsi adan bmenghitung dari nol, saya akan merekomendasikan a > 0 == b > 0. Jika Anda bersikeras untuk mengambil keuntungan dari kebenaran nilai bukan nol yang sewenang-wenang, !!varmenghasilkan nilai boolean 0/1 yang setara dengan var, sehingga Anda bisa menulis !!a == !!b, meskipun beberapa pembaca akan menganggapnya membingungkan.
Dale Hagglund
3
!a == !bjuga cukup untuk menguji kesetaraan, bukan nol menjadi nol, dan nol menjadi satu.
ryanpattison
5
@ rpattiso Anda memang benar, tentu saja, tapi saya rasa saya akan membaca !!a"konversi non-boolean ke nilai kebenaran yang setara", sedangkan saya akan membaca !a"secara logis membalikkan variabel boolean a". Secara khusus, saya akan mencari beberapa alasan spesifik inversi logis diinginkan.
Dale Hagglund
74

Ini adalah versi yang saya gunakan:

typedef enum { false = 0, true = !false } bool;

Karena false hanya memiliki satu nilai, tetapi true logis dapat memiliki banyak nilai, tetapi teknik menetapkan true menjadi apa yang akan digunakan oleh kompiler untuk kebalikan dari false.

Ini menangani masalah seseorang yang mengkode sesuatu yang akan menjadi seperti ini:

if (true == !false)

Saya pikir kita semua akan setuju bahwa itu bukan praktik yang baik, tetapi untuk satu kali biaya melakukan "true =! False" kita menghilangkan masalah itu.

[EDIT] Pada akhirnya saya menggunakan:

typedef enum { myfalse = 0, mytrue = !myfalse } mybool;

untuk menghindari tabrakan nama dengan skema lain yang mendefinisikan truedanfalse . Namun konsepnya tetap sama.

[EDIT] Untuk menampilkan konversi integer ke boolean:

mybool somebool;
int someint = 5;
somebool = !!someint;

Yang pertama (paling kanan)! mengkonversi bilangan nol ke nol, kemudian bilangan bulat kedua (paling kiri)! mengkonversi 0 ke amyfalse nilai. Saya akan meninggalkannya sebagai latihan bagi pembaca untuk mengkonversi bilangan bulat nol.

[EDIT] Ini adalah gaya saya untuk menggunakan pengaturan eksplisit dari nilai dalam enum ketika nilai spesifik diperlukan bahkan jika nilai defaultnya akan sama. Contoh: Karena false harus nol saya gunakan false = 0,daripadafalse,

Michael Potter
sumber
5
Juga manfaat lain untuk menggunakan enums adalah integrasi IDE - true, falsedan booldisorot di sebagian besar IDE karena mereka adalah nilai enum dan typedef, sebagai lawan dari #defines, yang jarang disorot oleh sintaks.
Penasaran: Mengabaikan apakah itu benar-benar berfungsi atau tidak, apakah valid C (99+) untuk mengizinkan enum untuk referensi nilai sebelumnya dalam enumerasi yang sama ?
@ tgm1024 gcc -ansi -pedantic -Walltidak memberikan peringatan, jadi saya percaya gcc; Jika ini berhasil bahkan untuk c89itu harus bekerja c99juga.
yyny
1
"Karena false hanya memiliki satu nilai, tetapi true logical dapat memiliki banyak nilai, tetapi teknik menetapkan true sebagai apa yang akan digunakan oleh kompiler untuk kebalikan dari false." Operator negasi !hanya dapat mengembalikan nilai 0dan 1, jadi true = !falseakan selalu memberikan nilai 1. Metode ini tidak memberikan keamanan ekstra typedef enum { false, true } bool;.
user694733
1
Yang paling awal saya temukan adalah dari C90 (6.3.3.3 operator aritmatika unary): "Hasil operator negasi logis! Adalah 0 jika nilai operand-nya tidak sama dengan 0. 1 jika nilai operan-nya sama dengan 0. hasilnya bertipe int. Ekspresi! E setara dengan (O == E). " Itu harus mencakup setiap kompiler yang pernah mengklaim mendukung standar C. Kompiler tentu saja dapat secara hukum mengabaikan aturan ini dalam kasus di mana tidak masalah untuk perilaku yang dapat diamati (seperti if(!value)), tetapi pengecualian itu tidak berlaku dalam kasus khusus ini.
user694733
30

Hal pertama yang pertama. C, yaitu ISO / IEC 9899 telah memiliki tipe boolean selama 19 tahun sekarang . Itu adalah waktu yang jauh lebih lama daripada yang diharapkan dari karir pemrograman C dengan bagian-bagian amatir / akademik / profesional digabungkan ketika mengunjungi pertanyaan ini . Milik saya memang melampaui itu mungkin hanya 1-2 tahun. Ini berarti bahwa selama waktu rata-rata pembaca telah belajar apa pun tentang C, C sebenarnya telah memiliki tipe data boolean .

Untuk tipe data #include <stdbool.h>,, dan gunakan true, falsedan bool. Atau jangan memasukkannya, dan gunakan _Bool, 1dan 0sebagai gantinya.


Ada berbagai praktik berbahaya yang dipromosikan dalam jawaban lain untuk utas ini. Saya akan mengatasinya:

typedef int bool;
#define true 1
#define false 0

Ini tidak-tidak, karena pembaca biasa - yang memang belajar C dalam 19 tahun itu - akan mengharapkan yang boolmengacu pada tipe data aktual bool dan akan berperilaku sama, tetapi tidak! Sebagai contoh

double a = ...;
bool b = a;

Dengan C99 bool/ _Bool, bakan diatur ke false iff a adalah nol, dan truesebaliknya. C11 6.3.1.2p1

  1. Ketika nilai skalar apa pun dikonversi menjadi _Bool, hasilnya adalah 0 jika nilainya sebanding dengan 0; jika tidak, hasilnya adalah 1. 59)

Catatan kaki

59) NaNs tidak membandingkan sama dengan 0 dan dengan demikian dikonversi ke 1.

Dengan typedefdi tempat, doubleakan dipaksa ke int- jika nilai ganda tidak dalam kisaranint , perilaku tidak terdefinisi .

Secara alami hal yang sama berlaku untuk if true dan falsedinyatakan dalamenum .

Apa yang lebih berbahaya adalah menyatakan

typedef enum bool {
    false, true
} bool;

karena sekarang semua nilai selain 1 dan 0 tidak valid, dan jika nilai seperti itu diberikan ke variabel jenis itu, perilaku akan sepenuhnya tidak terdefinisi .

Karena itu jika Anda tidak dapat menggunakan C99 karena alasan yang tidak dapat dijelaskan, untuk variabel boolean Anda harus menggunakan:

  • jenis intdan nilai 0dan1 apa adanya ; dan hati-hati lakukan konversi domain dari nilai-nilai lain ke ini dengan negasi ganda!!
  • atau jika Anda bersikeras Anda tidak ingat bahwa 0 adalah falsy dan non-nol Truish, setidaknya menggunakan huruf sehingga mereka tidak bingung dengan konsep C99: BOOL, TRUEdan FALSE!
Antti Haapala
sumber
1
Apa bagian dari Standar C yang akan membatasi objek tipe enumerasi untuk memegang nilai-nilai yang tercantum secara eksplisit di dalamnya? Jika nilai terbesar untuk konstanta enumerasi kurang dari UCHAR_MAX atau USHRT_MAX, suatu implementasi dapat menggunakan tipe yang lebih kecil dari intatau unsigned intuntuk menahan enumerasi, tetapi saya tidak tahu apa-apa dalam Standar yang akan menyebabkan enumerasi berperilaku sebagai selain integer Tipe.
supercat
18
typedef enum {
    false = 0,
    true
} t_bool;
mouviciel
sumber
2
2 hingga MAX_INT harus dievaluasi juga benar
technosaurus
2
@ technosaurus Mengambil pendekatan ini tidak menjamin! false == true karena! false dapat berupa angka yang bukan nol. Sebuah solusi sederhana untuk secara eksplisit menetapkan true to! False.
Andrew
3
@Andrew Itu tidak benar. !0 = 1oleh standar C, dan !a = 0untuk nilai bukan nol dari a. Masalahnya adalah bahwa setiap non-nol dianggap benar. Jadi jika adan bkeduanya "benar", itu tidak selalu berarti `a == b`.
Jeremy West
14

C memiliki tipe boolean: bool (setidaknya selama 10 (!) Tahun terakhir)

Sertakan stdbool.h dan true / false akan berfungsi seperti yang diharapkan.

tuan
sumber
12
10 tahun dalam standar, tetapi tidak 10 tahun dalam kompiler! Kompilasi C MSVC ++ tidak mendukung C99 sama sekali selain mengizinkan // komentar, dan tidak mungkin melakukannya. _Bool juga didefinisikan dalam C99 sebagai tipe bawaan, sedangkan bool adalah typedef pada header <stdbool.h>.
Clifford
5
@Clifford 4 tahun berlalu sejak komentar Anda ... tidak ada yang berubah. MSVC adalah kompiler C ++ dan saya percaya MS telah mengatakan bahwa mereka tidak benar-benar tertarik untuk mendukung semua fitur C baru (C99 & C11). Tapi saya tidak bisa menganggap bahwa MSVC tidak mendukung fitur C baru sebagai alasan (terutama ketika Anda mengatakannya terhadap 10 tahun pada jawaban). 10 tahun adalah waktu yang sangat lama di dunia pemrograman. Setiap kompiler yang layak harus memiliki dukungan untuknya dalam waktu kurang dari 10 tahun jika vendor dimaksudkan untuk mendukungnya.
PP
2
@ RajaIndian: Saya tidak yakin mengapa Anda mengarahkan komentar Anda kepada saya atau bahkan merasa perlu berkomentar sama sekali. Saya hanya menyatakan situasi yang ada pada saat penulisan. Saya tidak mendukung situasi itu, hanya menunjukkan bahwa "jawaban" mungkin tidak berlaku dalam semua keadaan.
Clifford
@Clifford: Secara ketat, standar boolharus makro yang diperluas _Bool. Perbedaannya penting karena Anda bisa #undefmakro (dan itu diizinkan, setidaknya sebagai ukuran transisi), tetapi Anda tidak untypedefbisa mengetik. Itu tidak mengubah dorongan utama dari komentar pertama Anda.
Jonathan Leffler
2
VS2015 dan yang lebih baru (& mungkin sebelumnya, sampai titik tertentu) tidak memiliki masalah dengan boolmelalui di <stdbool.h>bawah kompilasi C. Itu memutuskan untuk _Bool.
11

Apa pun yang bukan nol dievaluasi benar dalam operasi boolean, jadi Anda bisa saja

#define TRUE 1
#define FALSE 0

dan gunakan konstanta.

ggambett
sumber
10
tetapi gunakan dengan hati-hati: karena hasil yang sebenarnya bisa berupa nilai bukan nol, tes jika (t == BENAR) {...} dan jika (t), yang setara dalam bahasa lain, tidak setara dalam C .
Fortega
1
Anda benar, tetapi itu juga berlaku di C ++ yang memang memiliki tipe bool, bukan? Selama debugging saya telah melihat variabel bool dengan nilai-nilai 5837834939 ...
ggambett
1
Dalam C ++, tes if (t == true) sama dengan tes if (t), karena C ++ melakukan beberapa konversi (semua yang bukan 0 atau nilai null pointer dikonversi menjadi true)
Fortega
6
Yang harus Anda asumsikan tentang nilai sebenarnya boolean adalah bahwa itu bukan nol. Jadi kode seperti jika (b) aman sementara jika (b == BENAR) tidak; yang terakhir adalah praktik buruk (dan tidak ada gunanya).
Clifford
5

Hanya pelengkap jawaban lain dan klarifikasi, jika Anda diizinkan menggunakan C99.

+-------+----------------+-------------------------+--------------------+
|  Name | Characteristic | Dependence in stdbool.h |        Value       |
+-------+----------------+-------------------------+--------------------+
| _Bool |   Native type  |    Don't need header    |                    |
+-------+----------------+-------------------------+--------------------+
|  bool |      Macro     |           Yes           | Translate to _Bool |
+-------+----------------+-------------------------+--------------------+
|  true |      Macro     |           Yes           |   Translate to 1   |
+-------+----------------+-------------------------+--------------------+
| false |      Macro     |           Yes           |   Translate to 0   |
+-------+----------------+-------------------------+--------------------+

Beberapa preferensi saya:

  • _Boolatau bool? Keduanya baik-baik saja, tetapi boolterlihat lebih baik daripada kata kunci_Bool .
  • Nilai yang diterima untuk booldan _Booladalah: falseatau true. Menetapkan 0atau 1bukannya falseatau truevalid, tetapi lebih sulit untuk membaca dan memahami aliran logika.

Beberapa info dari standar:

  • _BoolTIDAK unsigned int, tetapi merupakan bagian dari grup tipe integer yang tidak ditandai . Cukup besar untuk menampung nilai 0atau1 .
  • JANGAN, tapi ya, Anda bisa mendefinisikan ulang bool truedanfalse tetapi tentu saja itu bukan ide yang baik. Kemampuan ini dianggap usang dan akan dihapus di masa depan.
  • Menetapkan jenis skalar (tipe aritmatika dan tipe penunjuk) ke _Boolatau bool, jika nilai skalar sama 0atau membandingkannya dengan 0itu 0, jika tidak hasilnya adalah 1: _Bool x = 9; 9dikonversi menjadi 1ketika ditugaskan x.
  • _Booladalah 1 byte (8 bit), biasanya programmer tergoda untuk mencoba menggunakan bit lainnya, tetapi tidak disarankan, karena satu-satunya jaminan yang diberikan adalah bahwa hanya satu bit yang digunakan untuk menyimpan data, tidak seperti tipe charyang memiliki 8 bit tersedia.
Perilaku tidak terdefinisi
sumber
2

Ini dia:

#define TRUE 1
#define FALSE 0
RngTng
sumber
7
Id pergi dengan sesuatu seperti #define TRUE! FALSE
Tom
2

Anda dapat menggunakan arang, atau wadah nomor kecil lainnya untuknya.

Kode semu

#define TRUE  1
#define FALSE 0

char bValue = TRUE;
Filip Ekberg
sumber
Juga di C biasanya int, dan dapat menyebabkan hilangnya peringatan presisi dengan kode lain yang menggunakan int ..
Thomas Bonini
Kecuali jika Anda mengoptimalkan ruang secara manual, selalu lebih baik menggunakan ukuran kata normal perangkat keras (misalnya: biasanya int), karena pada beberapa arsitektur Anda mendapatkan hasil kinerja yang signifikan karena harus membongkar / menutupi pemeriksaan pada variabel-variabel ini.
Kingsley
2

Anda bisa menggunakan _Bool, tetapi nilai balik harus berupa bilangan bulat (1 untuk true, 0 untuk false). Namun, disarankan untuk memasukkan dan menggunakan bool seperti dalam C ++, seperti yang dikatakan dalam balasan ini dari forum daniweb , serta jawaban ini , dari pertanyaan stackoverflow lainnya:

_Bool: tipe boolean C99. Menggunakan _Bool secara langsung hanya disarankan jika Anda mempertahankan kode lawas yang sudah mendefinisikan makro untuk bool, true, atau false. Kalau tidak, makro-makro itu distandarkan di header. Sertakan header itu dan Anda dapat menggunakan bool seperti yang Anda lakukan di C ++.

Lokian
sumber
2

Ekspresi bersyarat dianggap benar jika tidak nol, tetapi standar C mengharuskan operator logika itu sendiri mengembalikan 0 atau 1.

@Tom: #define TRUE! FALSE buruk dan sama sekali tidak ada gunanya. Jika file header masuk ke kode C ++ yang dikompilasi, maka itu dapat menyebabkan masalah:

void foo(bool flag);

...

int flag = TRUE;
foo(flag);

Beberapa kompiler akan menghasilkan peringatan tentang konversi bool int =>. Terkadang orang menghindari ini dengan melakukan:

foo(flag == TRUE);

untuk memaksa ekspresi menjadi bool C ++. Tetapi jika Anda #menentukan BENAR! SALAH, Anda berakhir dengan:

foo(flag == !0);

yang akhirnya melakukan perbandingan int-to-bool yang dapat memicu peringatan itu.

jamesdlin
sumber
1

Jika Anda menggunakan C99 maka Anda dapat menggunakan _Booljenisnya. Tidak #includeperlu. Anda perlu memperlakukannya seperti integer, meskipun, di mana 1adalah truedan 0adalahfalse .

Anda kemudian dapat mendefinisikan TRUEdan FALSE.

_Bool this_is_a_Boolean_var = 1;


//or using it with true and false
#define TRUE 1
#define FALSE 0
_Bool var = TRUE;
That_Linux_Guy
sumber
Atau Anda bisa #include <stdbool.h>dan penggunaan bool, truedan falseseperti standar ingin Anda.
SS Anne
1

Saat ini C99 mendukung tipe boolean tetapi Anda harus melakukannya#include <stdbool.h> .

Contoh:

#include <stdbool.h>

int main() 
{ 
    bool arr[2] = {true, false}; 

    printf("%d\n", arr[0] && arr[1]);
    printf("%d\n", arr[0] || arr[1]);

    return 0; 
} 

Keluaran:

0
1
Kalana
sumber
0

Inilah yang saya gunakan:

enum {false, true};
typedef _Bool bool;

_Bool adalah tipe bawaan C. Ini dimaksudkan untuk nilai boolean.

pengguna12211554
sumber
-2

Anda cukup menggunakan #definearahan sebagai berikut:

#define TRUE 1
#define FALSE 0
#define NOT(arg) (arg == TRUE)? FALSE : TRUE
typedef int bool;

Dan gunakan sebagai berikut:

bool isVisible = FALSE;
bool isWorking = TRUE;
isVisible = NOT(isVisible);

dan seterusnya

Prakash Bhattarai
sumber
5
TIDAK makro harus dilindungi oleh kurung di sekitar argdan ekspresi secara keseluruhan: #define NOT(arg) (((arg) == TRUE) ? FALSE : TRUE). Namun, akan lebih baik untuk menguji kepalsuan (itu akan memberikan jawaban yang benar bahkan jika argitu 23 bukannya 0 atau 1:. #define NOT(arg) (((arg) == FALSE) ? TRUE : FALSE)Tetapi seluruh ekspresi dapat dikurangi menjadi #define NOT(arg) (!(arg)), tentu saja, yang menghasilkan hasil yang sama.
Jonathan Leffler