Saya telah melihat definisi dalam C
#define TRUE (1==1)
#define FALSE (!TRUE)
Apakah ini perlu? Apa manfaatnya dengan mendefinisikan TRUE sebagai 1, dan SALAH sebagai 0?
Saya telah melihat definisi dalam C
#define TRUE (1==1)
#define FALSE (!TRUE)
Apakah ini perlu? Apa manfaatnya dengan mendefinisikan TRUE sebagai 1, dan SALAH sebagai 0?
Jawaban:
Pendekatan ini akan menggunakan boolean
tipe aktual (dan menyelesaikan ke true
dan false
) jika kompiler mendukungnya. (khususnya, C ++)
Namun, akan lebih baik untuk memeriksa apakah C ++ sedang digunakan (melalui __cplusplus
makro) dan benar-benar menggunakan true
dan false
.
Dalam kompiler C, ini sama dengan 0
dan 1
.
(perhatikan bahwa menghapus tanda kurung akan merusak karena urutan operasi)
1==1
adalah int
. (lihat stackoverflow.com/questions/7687403/… .)
boolean
tipe?
true
atau false
.
#define TRUE true
dan #define FALSE false
kapan pun __cplusplus
didefinisikan.
Jawabannya adalah portabilitas. Nilai numerik TRUE
dan FALSE
tidak penting. Apa yang penting adalah bahwa pernyataan seperti if (1 < 2)
mengevaluasi ke if (TRUE)
dan pernyataan seperti if (1 > 2)
mengevaluasi ke if (FALSE)
.
Diberikan, dalam C, (1 < 2)
mengevaluasi 1
dan (1 > 2)
mengevaluasi 0
, sehingga seperti yang dikatakan orang lain, tidak ada perbedaan praktis sejauh menyangkut kompiler. Tetapi dengan membiarkan kompiler mendefinisikan TRUE
dan FALSE
sesuai dengan aturannya sendiri, Anda membuat maknanya secara eksplisit untuk programmer, dan Anda menjamin konsistensi dalam program Anda dan pustaka lainnya (dengan asumsi pustaka lain mengikuti standar C ... Anda akan terkesima).
Some History
Beberapa BASIC didefinisikan FALSE
sebagai 0
dan TRUE
sebagai -1
. Seperti banyak bahasa modern, mereka menafsirkan nilai bukan nol TRUE
, tetapi mereka mengevaluasi ekspresi boolean yang benar -1
. NOT
Operasi mereka dilaksanakan dengan menambahkan 1 dan membalik tanda, karena efisien untuk melakukannya dengan cara itu. Jadi 'TIDAK x' menjadi -(x+1)
. Efek samping dari hal ini adalah bahwa nilai suka 5
dievaluasi TRUE
, tetapi NOT 5
dievaluasi -6
, yang juga TRUE
! Menemukan bug semacam ini tidak menyenangkan.
Praktik Terbaik
Mengingat de facto aturan yang nol ditafsirkan sebagai FALSE
dan setiap nilai bukan nol ditafsirkan sebagai TRUE
, Anda harus tidak pernah membandingkan ekspresi boolean-mencari untuk TRUE
atauFALSE
. Contoh:
if (thisValue == FALSE) // Don't do this!
if (thatValue == TRUE) // Or this!
if (otherValue != TRUE) // Whatever you do, don't do this!
Mengapa? Karena banyak programmer menggunakan cara pintas memperlakukan int
s sebagai bool
s. Mereka tidak sama, tetapi umumnya kompiler mengizinkannya. Jadi, misalnya, sangat sah untuk menulis
if (strcmp(yourString, myString) == TRUE) // Wrong!!!
Itu terlihat sah, dan kompiler akan dengan senang hati menerimanya, tetapi mungkin tidak melakukan apa yang Anda inginkan. Itu karena nilai kembalinya strcmp()
adalah
0 jika yourString == myString
<0 jika yourString < myString
> 0 jikayourString > myString
Jadi baris di atas TRUE
hanya mengembalikan ketika yourString > myString
.
Cara yang tepat untuk melakukan ini adalah baik
// Valid, but still treats int as bool.
if (strcmp(yourString, myString))
atau
// Better: lingustically clear, compiler will optimize.
if (strcmp(yourString, myString) != 0)
Demikian pula:
if (someBoolValue == FALSE) // Redundant.
if (!someBoolValue) // Better.
return (x > 0) ? TRUE : FALSE; // You're fired.
return (x > 0); // Simpler, clearer, correct.
if (ptr == NULL) // Perfect: compares pointers.
if (!ptr) // Sleazy, but short and valid.
if (ptr == FALSE) // Whatisthisidonteven.
Anda akan sering menemukan beberapa "contoh buruk" ini dalam kode produksi, dan banyak pemrogram berpengalaman bersumpah dengan mereka: mereka bekerja, ada yang lebih pendek daripada alternatif mereka yang benar (pedantically?), Dan idiom-idiom tersebut hampir dikenal secara universal. Tetapi pertimbangkan: versi "benar" tidak kurang efisien, mereka dijamin portabel, mereka akan lulus bahkan pada tingkat yang paling ketat, dan bahkan pemrogram baru akan memahaminya.
Bukankah itu sepadan?
(1==1)
tidak lebih portabel daripada 1
. Aturan kompiler sendiri adalah dari bahasa C, yang jelas dan tidak ambigu tentang semantik kesetaraan dan operator relasional. Saya belum pernah melihat seorang kompiler membuat kesalahan ini.
strcmp
diketahui kurang dari, sama atau lebih besar dari 0. Tidak dijamin menjadi -1, 0 atau 1 dan ada platform di alam bebas yang tidak mengembalikan nilai-nilai itu untuk mendapatkan kecepatan implementasi. Jadi kalau strcmp(a, b) == TRUE
begitu a > b
tetapi implikasi sebaliknya mungkin tidak berlaku.
(1==1)
dan 1
keduanya merupakan ekspresi tipe konstan int
dengan nilai 1. Keduanya identik secara semantik. Saya kira Anda dapat menulis kode yang melayani pembaca yang tidak tahu itu, tetapi di mana itu berakhir?
The (1 == 1)
Trik ini berguna untuk mendefinisikan TRUE
dengan cara yang transparan untuk C, namun menyediakan mengetik yang lebih baik di C ++. Kode yang sama dapat ditafsirkan sebagai C atau C ++ jika Anda menulis dalam dialek yang disebut "Bersihkan C" (yang mengkompilasi sebagai C atau C ++) atau jika Anda menulis file header API yang dapat digunakan oleh programmer C atau C ++.
Dalam unit terjemahan C, 1 == 1
memiliki arti yang sama persis seperti 1
; dan 1 == 0
memiliki arti yang sama dengan 0
. Namun, dalam unit terjemahan C ++, 1 == 1
memiliki tipe bool
. Jadi TRUE
makro didefinisikan dengan cara itu mengintegrasikan lebih baik ke C ++.
Contoh bagaimana itu terintegrasi lebih baik adalah bahwa misalnya jika fungsi foo
memiliki kelebihan untuk int
dan untuk bool
, maka foo(TRUE)
akan memilih bool
kelebihan. Jika TRUE
hanya didefinisikan sebagai 1
, maka itu tidak akan berfungsi dengan baik di C ++. foo(TRUE)
akan menginginkan int
kelebihan.
Tentu saja, C99 diperkenalkan bool
, true
, dan false
dan ini dapat digunakan di file header yang bekerja dengan C99 dan dengan C.
Namun:
TRUE
dan FALSE
sebagai (0==0)
dan (1==0)
sebelum C99.Jika Anda bekerja dalam proyek campuran C dan C ++, dan tidak ingin C99, tentukan huruf kecil true
, false
dan bool
sebagai gantinya.
#ifndef __cplusplus
typedef int bool;
#define true (0==0)
#define false (!true)
#endif
Yang sedang berkata, 0==0
trik itu (adalah?) Digunakan oleh beberapa programmer bahkan dalam kode yang tidak pernah dimaksudkan untuk beroperasi dengan C ++ dengan cara apa pun. Itu tidak membeli apa pun dan menunjukkan bahwa programmer memiliki kesalahpahaman tentang cara kerja boolean di C.
Jika penjelasan C ++ tidak jelas, berikut ini adalah program uji:
#include <cstdio>
void foo(bool x)
{
std::puts("bool");
}
void foo(int x)
{
std::puts("int");
}
int main()
{
foo(1 == 1);
foo(1);
return 0;
}
Hasil:
bool
int
Adapun pertanyaan dari komentar tentang bagaimana kelebihan fungsi C ++ relevan dengan pemrograman campuran C dan C ++. Ini hanya menggambarkan perbedaan tipe. Alasan yang valid untuk menginginkan true
konstanta bool
ketika dikompilasi sebagai C ++ adalah untuk diagnostik yang bersih. Pada tingkat peringatan tertinggi, kompiler C ++ mungkin memperingatkan kita tentang konversi jika kita melewatkan integer sebagai bool
parameter. Salah satu alasan penulisan Clean C bukan hanya karena kode kami lebih portabel (karena dipahami oleh kompiler C ++, tidak hanya kompiler C), tetapi kita dapat mengambil manfaat dari pendapat diagnostik kompiler C ++.
TRUE
akan berbeda di bawah C ++.
#ifdef __cplusplus
untuk mengekspresikan maksud Anda dengan lebih jelas.
bool
dan int
tidak terlalu penting dalam praktik, karena semuanya secara implisit dapat dikonversi satu sama lain (dan dalam C sebenarnya "sama" , catat tanda kutipnya. , meskipun) dan tidak ada banyak situasi di mana Anda benar-benar perlu memisahkan diri di antara keduanya. "tidak banyak" mungkin terlalu berat, "jauh lebih sedikit dibandingkan dengan kode yang menggunakan template dan kelebihan beban" mungkin lebih baik.
#define TRUE (1==1)
#define FALSE (!TRUE)
setara dengan
#define TRUE 1
#define FALSE 0
dalam C.
Hasil dari operator relasional adalah 0
atau 1
. 1==1
dijamin untuk dievaluasi 1
dan !(1==1)
dijamin untuk dievaluasi 0
.
Sama sekali tidak ada alasan untuk menggunakan formulir pertama. Perhatikan bahwa bentuk pertama tidak kurang efisien karena pada hampir semua kompiler ekspresi konstan dievaluasi pada waktu kompilasi daripada pada saat run-time. Ini diizinkan menurut aturan ini:
(C99, 6.6p2) "Ekspresi konstan dapat dievaluasi selama penerjemahan daripada runtime, dan karenanya dapat digunakan di sembarang tempat yang mungkin berupa konstanta."
PC-Lint bahkan akan mengeluarkan pesan (506, nilai konstan boolean) jika Anda tidak menggunakan literal untuk TRUE
dan FALSE
makro:
Untuk C,
TRUE
harus didefinisikan sebagai1
. Namun, bahasa lain menggunakan jumlah selain 1 sehingga beberapa programmer merasa!0
bermain aman.
Juga di C99, stdbool.h
definisi untuk makro boolean true
dan false
langsung menggunakan literal:
#define true 1
#define false 0
1==1
dijamin akan dievaluasi ke1
if(foo == true)
, yang akan berubah dari sekadar praktik buruk menjadi buggy.
(x == TRUE)
dapat memiliki nilai kebenaran yang berbeda dari x
.
Selain C ++ (sudah disebutkan), manfaat lain adalah untuk alat analisis statis. Kompiler akan menghapus semua inefisiensi, tetapi penganalisa statis dapat menggunakan tipe abstraknya sendiri untuk membedakan antara hasil perbandingan dan tipe integer lainnya, sehingga ia mengetahui secara implisit bahwa TRUE harus merupakan hasil perbandingan dan tidak boleh dianggap kompatibel dengan bilangan bulat.
Jelas C mengatakan bahwa mereka kompatibel, tetapi Anda dapat memilih untuk tidak sengaja menggunakan fitur itu untuk membantu menyoroti bug - misalnya, di mana seseorang mungkin bingung &
dan &&
, atau mereka telah mengacaukan prioritas operator mereka.
if (boolean_var == TRUE)
dengan cara ekspansi if (boolean_var == (1 == 1))
yang berkat info tipe ditingkatkan dari (1 == 1)
node jatuh ke dalam pola if (<*> == <boolean_expr>)
.
Perbedaan praktisnya tidak ada. 0
dievaluasi ke false
dan 1
dievaluasi ke true
. Fakta bahwa Anda menggunakan ekspresi boolean ( 1 == 1
) atau 1
, untuk mendefinisikan true
, tidak ada bedanya. Keduanya dievaluasi int
.
Perhatikan bahwa C library standar menyediakan header khusus untuk mendefinisikan boolean: stdbool.h
.
true
dievaluasi ke 1
dan false
dievaluasi ke 0
. C tidak tahu tentang tipe boolean asli, mereka hanya int.
int
, dengan nilai 0
atau 1
. C memang memiliki tipe boolean yang sebenarnya ( _Bool
, dengan makro yang bool
didefinisikan <stdbool.h>
, tetapi itu hanya ditambahkan dalam C99, yang tidak mengubah semantik operator untuk menggunakan tipe baru.
_Bool
, dan <stdbool.h>
telah #define bool _Bool
.
1 == 1
yang dievaluasi sebagai int
. Diedit.
Kami tidak tahu nilai pasti bahwa TRUE sama dengan dan kompiler dapat memiliki definisi sendiri. Jadi apa yang Anda privode adalah menggunakan definisi internal kompiler. Ini tidak selalu diperlukan jika Anda memiliki kebiasaan pemrograman yang baik tetapi dapat menghindari masalah untuk beberapa gaya pengkodean yang buruk, misalnya:
if ((a> b) == BENAR)
Ini bisa menjadi bencana jika Anda mendefinisikan TRUE secara manual sebagai 1, sedangkan nilai internal TRUE adalah nilai lain.
>
operator selalu menghasilkan 1 untuk true, 0 untuk false. Tidak ada kemungkinan kompiler C mendapatkan kesalahan ini. Perbandingan kesetaraan TRUE
dan FALSE
gaya yang buruk; di atas lebih jelas ditulis sebagai if (a > b)
. Tetapi gagasan bahwa penyusun C yang berbeda dapat memperlakukan kebenaran dan salah secara berbeda sama sekali salah.
Biasanya dalam Bahasa Pemrograman C, 1 didefinisikan sebagai benar dan 0 didefinisikan sebagai salah. Karenanya mengapa Anda sering melihat hal berikut:
#define TRUE 1
#define FALSE 0
Namun, angka apa pun yang tidak sama dengan 0 akan dievaluasi menjadi benar juga dalam pernyataan bersyarat. Oleh karena itu dengan menggunakan di bawah ini:
#define TRUE (1==1)
#define FALSE (!TRUE)
Anda dapat secara eksplisit menunjukkan bahwa Anda mencoba untuk bermain aman dengan membuat kesalahan sama dengan apa pun yang tidak benar.
#define TRUE (’/’/’/’)
:;#define FALSE (’-’-’-’)
(diambil dari coding-guidelines.com/cbook/cbook1_1.pdf halaman 871)