Apakah ada perbedaan antara YA / TIDAK, BENAR / SALAH dan benar / salah dalam tujuan-c?

154

Pertanyaan sederhana sebenarnya; apakah ada perbedaan antara nilai-nilai ini (dan apakah ada perbedaan antara BOOL dan bool)? Seorang rekan kerja menyebutkan bahwa mereka mengevaluasi hal-hal yang berbeda di Objective-C, tetapi ketika saya melihat typedef di masing-masing file .h mereka, YA / BENAR / benar semuanya didefinisikan sebagai 1dan TIDAK / SALAH / salah semuanya didefinisikan sebagai 0. Apakah memang ada perbedaan?

Kevlar
sumber
5
Dari sudut pandang praktis tidak ada perbedaan. Anda mungkin dapat melakukan berbagai trik untuk menunjukkan perbedaan, tetapi Anda umumnya akan menyimpang ke wilayah "perilaku tidak terdefinisi".
Hot Licks

Jawaban:

84

Tidak ada perbedaan praktis asalkan Anda menggunakan BOOLvariabel sebagai boolean. C memproses ekspresi boolean berdasarkan pada apakah mereka mengevaluasi ke 0 atau tidak 0. Jadi:

if(someVar ) { ... }
if(!someVar) { ... }

artinya sama dengan

if(someVar!=0) { ... }
if(someVar==0) { ... }

itulah sebabnya Anda dapat mengevaluasi tipe atau ekspresi primitif apa pun sebagai tes boolean (termasuk, misalnya pointer). Perhatikan bahwa Anda harus melakukan yang pertama, bukan yang terakhir.

Perhatikan bahwa ada adalah perbedaan jika Anda menetapkan nilai tumpul untuk yang disebut BOOLvariabel dan uji untuk nilai-nilai tertentu, sehingga selalu menggunakan mereka sebagai boolean dan hanya menetapkan mereka dari mereka #definenilai-nilai.

Yang penting, jangan pernah menguji boolean menggunakan perbandingan karakter - itu tidak hanya berisiko karena someVardapat diberi nilai bukan nol yang bukan YA, tetapi, menurut saya yang lebih penting, gagal mengekspresikan maksud dengan benar:

if(someVar==YES) { ... } // don't do this!
if(someVar==NO ) { ... } // don't do this either!

Dengan kata lain, gunakan konstruksi seperti yang dimaksudkan dan didokumentasikan untuk digunakan dan Anda akan menyelamatkan diri dari dunia yang terluka di C.

Lawrence Dol
sumber
100

Saya percaya ada adalah perbedaan antara booldan BOOL, memeriksa halaman web ini untuk penjelasan mengapa:
http://iosdevelopertips.com/objective-c/of-bool-and-yes.html

Karena BOOLmerupakan unsigned charbukan tipe primitif, variabel jenis BOOLdapat berisi nilai-nilai selain YESdan NO.

Pertimbangkan kode ini:

BOOL b = 42;

if (b) {
    printf("b is not NO!\n");
}

if (b != YES) {
    printf("b is not YES!\n");
}

Outputnya adalah:

b bukan TIDAK!
b bukan YA!

Bagi kebanyakan orang ini adalah masalah yang tidak perlu, tetapi jika Anda benar-benar menginginkan boolean lebih baik menggunakan a bool. Saya harus menambahkan: iOS SDK biasanya digunakan BOOLpada definisi antarmuka, sehingga merupakan argumen yang harus dipertahankan BOOL.

Dan J
sumber
5
Tetapi perhatikan bahwa implementasi C asli tidak bool, dan karenanya sudah menjadi tradisi untuk menggunakan intatau charsebagai Boolean, kadang-kadang dengan #define untuk menyembunyikan perbedaan dan kadang tidak. Bahkan, saya tidak yakin apakah standar saat ini perlu booldiimplementasikan dengan cara yang mencegah memeriksa struktur internal itu.
Hot Licks
1
Meskipun, yang pertama printfberbohong. Nilai btidak YES, itu "bukan nol", yang merupakan kondisi yang diuji. Jadi Anda harus memiliki printf("b is not zero"), yang belum tentu sama dengan YES. Dalam hal ini, bkeduanya "bukan nol" dan "bukan YA".
Lawrence Dol
Terima kasih Lawrence, saya telah membuat pembaruan di sepanjang jalur itu.
Dan J
Memang, saya tidak mendapatkan output kedua di Xcode 8.2. Di mana saya gagal?
Igor Kislyuk
1
@HotLicks tidak ada perbedaan inheren antara 0, bukan nol dan salah dan benar. Selama nilainya dimaksudkan sebagai boolean yang logis, ia akan selalu memiliki antarmuka ini untuk menjaga kompatibilitas biner. Masalahnya dimulai ketika Anda menggunakan non boolean yang tampak seperti boolean, misalnya fungsi entri aplikasi perpustakaan standar c, mengembalikan 0 pada kesuksesan, banyak yang akhirnya menganggap 0 ini sebagai boolean, padahal sebenarnya itu adalah enumerasi aplikasi yang ditentukan atau ditentukan pengguna nilai, yang callees sering berharap menjadi nol pada penghentian abnormal.
Dmitry
52

Saya melakukan tes lengkap tentang ini. Hasil saya harus berbicara sendiri:

//These will all print "1"
NSLog(@"%d", true == true);
NSLog(@"%d", TRUE == true);
NSLog(@"%d", YES  == true);
NSLog(@"%d", true == TRUE);
NSLog(@"%d", TRUE == TRUE);
NSLog(@"%d", YES  == TRUE);
NSLog(@"%d", true == YES);
NSLog(@"%d", TRUE == YES);
NSLog(@"%d", YES  == YES);

NSLog(@"%d", false == false);
NSLog(@"%d", FALSE == false);
NSLog(@"%d", NO    == false);
NSLog(@"%d", false == FALSE);
NSLog(@"%d", FALSE == FALSE);
NSLog(@"%d", NO    == FALSE);
NSLog(@"%d", false == NO);
NSLog(@"%d", FALSE == NO);
NSLog(@"%d", NO    == NO);


//These will all print "0"
NSLog(@"%d", false == true);
NSLog(@"%d", FALSE == true);
NSLog(@"%d", NO    == true);
NSLog(@"%d", false == TRUE);
NSLog(@"%d", FALSE == TRUE);
NSLog(@"%d", NO    == TRUE);
NSLog(@"%d", false == YES);
NSLog(@"%d", FALSE == YES);
NSLog(@"%d", NO    == YES);

NSLog(@"%d", true == false);
NSLog(@"%d", TRUE == false);
NSLog(@"%d", YES  == false);
NSLog(@"%d", true == FALSE);
NSLog(@"%d", TRUE == FALSE);
NSLog(@"%d", YES  == FALSE);
NSLog(@"%d", true == NO);
NSLog(@"%d", TRUE == NO);
NSLog(@"%d", YES  == NO);

Outputnya adalah:

2013-02-19 20:30:37.061 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.061 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.072 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.073 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.073 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.074 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.074 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.075 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.075 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.076 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.077 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.077 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.078 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.078 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.079 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.079 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.080 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.080 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.081 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.081 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.082 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.091 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.092 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.093 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.093 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.094 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.094 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.095 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.095 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.096 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.096 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.097 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.098 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.101 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.102 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.102 BooleanTests[27433:a0f] 0
Supuhstar
sumber
3
[[NSObject] alokasi] init] tidak sama dengan BENAR atau YA. Jadi menguji inisialisasi objek dengan if ([[NSObject] alokasi] init] == ​​BENAR) akan gagal. Saya tidak pernah merasa nyaman dengan Bahasa yang mendefinisikan nilai "benar" tunggal padahal sebenarnya nilai yang tidak nol akan berlaku.
DrFloyd5
3
@SamuelRenkert Saya tidak pernah merasa nyaman dengan bahasa yang mengambil nilai non-Boolean dalam ifatau while. Seperti ... while("guitar gently weeps")seharusnya tidak bekerja ...
Supuhstar
@SamuelRenkert juga merupakan pintu belakang Linux yang ditemukan pada tahun 2003:if (user_id = ROOT_UID)
Supuhstar
14

Anda mungkin ingin membaca jawaban untuk pertanyaan ini . Singkatnya, di Objective-C (dari definisi di objc.h):

typedef signed char        BOOL; 
// BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C" 
// even if -funsigned-char is used.
#define OBJC_BOOL_DEFINED


#define YES             (BOOL)1
#define NO              (BOOL)0
Barry Wark
sumber
11

Perbedaan utama (berbahaya!) Antara truedan YESdalam serialisasi JSON.

Sebagai contoh, kami memiliki permintaan server tipe JSON dan perlu mengirim true / false di json sence:

NSDictionary *r1 = @{@"bool" : @(true)};
NSDictionary *r2 = @{@"bool" : @(YES)};
NSDictionary *r3 = @{@"bool" : @((BOOL)true)};

Kemudian kami mengonversinya menjadi string JSON sebelum mengirim sebagai

NSData *data = [NSJSONSerialization  dataWithJSONObject:requestParams options:0 error:nil];
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

Hasilnya adalah

jsonString1 // {"bool":1}
jsonString2 // {"bool":true}
jsonString3 // {"bool":true}

Karena logika API jsonString1dapat mengakibatkan kesalahan.

Jadi berhati-hatilah dengan booleans di Objective-C.

Singkatnya, hanya tepat @YESdan nilai dicor sebagai @((BOOL)expression)yang dari __NSCFBooleanjenis dan dikonversi ke truedengan JSON serialisasi. Ekspresi lain seperti @(expression1 && expression2)( datar @(YES && YES)) adalah __NSCFNumber (int)tipe dan dikonversi ke 1dalam JSON.

PS Anda cukup menggunakan boolean bernilai string

@{@"bool" : @"true"}; // in JSON {"bool":true}
malex
sumber
1

Ada bug halus yang tidak ada yang disebutkan di sini, yang saya pikir saya akan memasukkan ... lebih dari kesalahan logis daripada apa pun:

int i = 2;
if(i);        //true
if(i==YES);   // false
if((!!i)==YES); //true

jadi masalahnya di sini hanya itu (YES==1)dan di C perbandingannya bukan boolean, tetapi berdasarkan nilai.

karena YESitu hanya #define(bukan sesuatu yang intrinsik bagi bahasa), itu harus bernilai, dan 1paling masuk akal.

Grady Player
sumber
Ini pada dasarnya jawaban yang sama dengan DanJ, ​​dari 2+ tahun sebelumnya, dengan kurang detail.
Lawrence Dol
@LawrenceDol Saya tidak tahu, itu menyebutkan bahwa YA hanya #definisi menjadi 1 dan tidak intrinsik ke bahasa, seperti itu mungkin dalam bahasa tingkat yang lebih tinggi ... seseorang mungkin bisa mendapatkan nilai dari itu ... tapi bagus trolling, denganmu.
Pemain Grady
0

Saya pikir mereka menambahkan YA / TIDAK untuk lebih jelas dalam banyak kasus. Sebagai contoh:

[button setHidden:YES];

terdengar lebih baik daripada

[button setHidden:TRUE];
Marco
sumber
2
Saya tidak setuju; mereka berdua membaca yang sama, untukku. Namun, di UI untuk orang awam saya pikir Ya / Tidak terlihat lebih bagus.
Lawrence Dol
16
Saya juga tidak setuju. Jika ada, itu terbaca buruk karena tidak berpegang teguh pada standar tidak tertulis yang telah digunakan selama bertahun-tahun dalam bahasa lain. IE adalah contoh utama dari apa yang terjadi ketika Anda gagal mematuhi sejumlah besar standar.
FreeAsInBeer
1
Setengah downvote untuk 2 jawaban tidak tepat dan setengah downvote untuk menandatangani jawaban Anda
fpg1503
-2

Pertama mari kita periksa apa yang benar dan salah dan apa yang memberi mereka arti di tempat pertama.

kita dapat membangun struktur yang disebut jika a maka b selain c dalam kalkulus lambda sebagai berikut:

(\ifThenElse. <use if then else>)(\a. \b. \c. a b c)

Dalam JavaScript, Ini terlihat seperti ini:

(function(ifThenElse) {
    // use ifThenElse
})(function(a) {
    return function(b) {
        return function(c) {
            return a(b)(c);
        };
    };
});

agar ifThenElse bermanfaat, kita memerlukan fungsi "true" yang memilih kanan atau kiri, dan melakukan itu sambil mengabaikan opsi lain, atau fungsi "false" yang memilih opsi "true" tidak mengambil.

Kita dapat mendefinisikan fungsi-fungsi ini sebagai berikut:

(\true. <use true>)(\a. \b. a) and (\false. <use false>)(\a. \b. b)

dalam JavaScript terlihat seperti ini:

(function(True) {
    // use True
})(function(a) {
     return function(b) {
         return a;
     }
});

(function(False) {
    // use True
})(function(a) {
     return function(b) {
         return b;
     }
});

sekarang kita bisa melakukan hal berikut

(\true. \false. \ifThenElse. \doThis. \doThat. ifThenElse true doThis doThat)
(\a. \b. a)(\a. \b. b)(\a. \b. \c. a b c)(\a. ())(\a. ())

dengan doThis dan doThat being (\ a. ()) karena lambda calculus tidak menawarkan layanan apa pun seperti pencetakan / matematika / string, yang bisa kita lakukan adalah tidak melakukan apa-apa dan mengatakan kita telah melakukannya (dan kemudian menipu dengan menggantinya dengan layanan di sistem kami yang memberikan efek samping yang kami inginkan)

jadi mari kita lihat ini dalam aksi.

(function(True) {
    return (function(False) {
        return (function(ifThenElse) {
            return (function(doThis) {
                return (function(doThat) {
                    return ifThenElse(True)(doThis)(doThat);
                });
            });
        });
    })
})(function(a) {
     return function(b) {
         return a;
     }
})(function(a) {
     return function(b) {
         return b;
     }
})(function(a) {
    return function(b) {
        return function(c) {
            return a(b)(c);
        };
    };
})(function(a) { console.log("you chose LEFT!"); })
(function(a) {console.log("you chose RIGHT");})();

Itu adalah lingkungan yang dalam yang dapat disederhanakan jika kita diizinkan menggunakan array / peta / argumen / atau lebih dari satu pernyataan untuk dipecah menjadi beberapa fungsi, tetapi saya ingin tetap murni seperti saya dapat membatasi diri pada fungsi tepat satu argumen hanya.

perhatikan bahwa nama Benar / Salah tidak memiliki signifikansi yang melekat, kita dapat dengan mudah mengubah nama mereka menjadi ya / tidak, kiri / kanan, kanan / kiri, nol / satu, apel / jeruk. Ini memiliki arti penting dalam pilihan apa pun yang dibuat, itu hanya disebabkan oleh jenis pemilih yang membuatnya. Jadi jika "KIRI" dicetak, kita tahu bahwa pemilih hanya bisa benar, dan berdasarkan pengetahuan ini kita dapat memandu keputusan kita selanjutnya.

Jadi untuk meringkas

function ChooseRight(left) {
    return function _ChooseRight_inner(right) {
        return right;
    }
}
function ChooseLeft(left) {
    return function _ChooseLeft_inner(right) {
        return left;
    }
}

var env = {
    '0': ChooseLeft,
    '1': ChooseRight,
    'false': ChooseRight,
    'true': ChooseLeft,
    'no': ChooseRight
    'yes': ChooseLeft,
    'snd': ChooseRight,
    'fst': ChooseLeft
};
var _0 = env['0'];
var _1 = env['1'];
var _true = env['true'];
var _false = env['false'];
var yes = env['yes'];
var no = env['no'];

// encodes church zero or one to boolean
function lambda_encodeBoolean(self) {
    return self(false)(true);
}
// decodes a Boolean to church zero or one
function lambda_decodeBoolean(self) {
    console.log(self, self ? env['true'] : env['false']);
    return self ? env['true'] : env['false'];
}

lambda_decodeBoolean('one' === 'two')(function() {
    console.log('one is two');
})(function() {
    console.log('one is not two');
})();

lambda_decodeBoolean('one' === 'one')(function() {
    console.log('one is one');
})(function() {
    console.log('one is not one');
})();
Dmitry
sumber
-7

Tidak, YA / TIDAK adalah cara yang berbeda untuk merujuk pada BENAR / SALAH (1/0)

Marco
sumber