Objective-C: BOOL vs bool

192

Saya melihat "tipe baru" BOOL( YES, NO).

Saya membaca bahwa jenis ini hampir seperti arang.

Untuk pengujian saya lakukan:

NSLog(@"Size of BOOL %d", sizeof(BOOL));
NSLog(@"Size of bool %d", sizeof(bool));

Baik untuk melihat bahwa kedua log menampilkan "1" (kadang-kadang di C ++ bool adalah int dan ukurannya 4)

Jadi saya hanya ingin tahu apakah ada beberapa masalah dengan tipe bool atau sesuatu?

Bisakah saya menggunakan bool (yang tampaknya berfungsi) tanpa kehilangan kecepatan?

Francescu
sumber

Jawaban:

198

Dari definisi dalam objc.h:

#if (TARGET_OS_IPHONE && __LP64__)  ||  TARGET_OS_WATCH
typedef bool BOOL;
#else
typedef signed char BOOL; 
// BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C" 
// even if -funsigned-char is used.
#endif

#define YES ((BOOL)1)
#define NO  ((BOOL)0)

Jadi, ya, Anda bisa berasumsi bahwa BOOL adalah char. Anda dapat menggunakan tipe (C99) bool, tetapi semua kerangka kerja Objective-C Apple dan sebagian besar kode Objective-C / Cocoa menggunakan BOOL, jadi Anda akan menyelamatkan diri dari sakit kepala jika typedef pernah berubah dengan hanya menggunakan BOOL.

Barry Wark
sumber
17
"Semua kerangka kerja Apple" - tidak benar. Lihatlah CGGeometry.h, khususnya: bool CG_INLINE __CGPointEqualToPoint (CGPoint point1, CGPoint point2) {return point1.x == point2.x && point1.y == point2.y; }
Elliot
58
@ Elliot Anda benar. Banyak kerangka kerja C (CoreFoundation, CoreGraphics, dll.) Menggunakan C99 bool. Semua kerangka kerja Objective-C digunakan BOOL.
Barry Wark
@ Cœur Anda telah mengedit definisi sampel kode BOOL, tetapi teks di bawahnya tetap sama. Agak membingungkan dan tidak benar. Lihat jawaban saya.
Penasaran
Harus tahu perilaku berbeda lihat di bawah ini. NSInteger progressTime = 2;//any value NSInteger totalTime = 1;//any value BOOL success = (progressTime>=totalTime)// itu selalu memberi NO But Once aku menerima (progressTime>=totalTime)nilai itu menjadi booltipe successitu mengembalikan hasil yang benar. Saya tidak mengerti perilaku ini. Saya menggunakan Xcode 7.xdan iOSversi itu 8.x. @BarryWark
Kamar Shad
34

Seperti disebutkan di atas, BOOL adalah char yang ditandatangani. bool - type dari standar C99 (int).

BOOL - YA / TIDAK. bool - benar / salah.

Lihat contoh:

bool b1 = 2;
if (b1) printf("REAL b1 \n");
if (b1 != true) printf("NOT REAL b1 \n");

BOOL b2 = 2;
if (b2) printf("REAL b2 \n");
if (b2 != YES) printf("NOT REAL b2 \n");

Dan hasilnya

NYATA b1
NYATA b2
TIDAK NYATA b2

Perhatikan bahwa bool! = BOOL. Hasil di bawah ini hanya SEKALI LAGI - NYATA b2

b2 = b1;
if (b2) printf("ONCE AGAIN - REAL b2 \n");
if (b2 != true) printf("ONCE AGAIN - NOT REAL b2 \n");

Jika Anda ingin mengonversi bool menjadi BOOL Anda harus menggunakan kode berikutnya

BOOL b22 = b1 ? YES : NO; //and back - bool b11 = b2 ? true : false;

Jadi, dalam kasus kami:

BOOL b22 = b1 ? 2 : NO;
if (b22)    printf("ONCE AGAIN MORE - REAL b22 \n");
if (b22 != YES) printf("ONCE AGAIN MORE- NOT REAL b22 \n");

Jadi .. apa yang kita dapatkan sekarang? :-)

berilium
sumber
3
Anda bisa, alih-alih menggunakan penggunaan operator ternary !!b1. Untuk mengkonversi di antara mereka
Richard J. Ross III
1
'NOT REAL b2' tidak dicetak pada simulator SE iPhone saya.
Pengobrol
12

Pada saat penulisan ini adalah versi terbaru dari objc.h:

/// Type to represent a boolean value.
#if (TARGET_OS_IPHONE && __LP64__)  ||  TARGET_OS_WATCH
#define OBJC_BOOL_IS_BOOL 1
typedef bool BOOL;
#else
#define OBJC_BOOL_IS_CHAR 1
typedef signed char BOOL; 
// BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C" 
// even if -funsigned-char is used.
#endif

Ini berarti bahwa pada perangkat iOS 64-bit dan pada WatchOS BOOLadalah hal yang persis sama seperti boolpada semua perangkat lain (OS X, iOS 32-bit) itu signed chardan bahkan tidak dapat ditimpa oleh flag compiler-funsigned-char

Ini juga berarti bahwa kode contoh ini akan berjalan secara berbeda pada platform yang berbeda (mengujinya sendiri):

int myValue = 256;
BOOL myBool = myValue;
if (myBool) {
    printf("i'm 64-bit iOS");
} else {
    printf("i'm 32-bit iOS");
}

BTW tidak pernah menetapkan hal-hal seperti array.countke BOOLvariabel karena sekitar 0,4% dari nilai yang mungkin akan negatif.

Piotr Tobolski
sumber
kompiler akan memunculkan kesalahan jika Anda menggunakan bool sebagai parameter blok yang didefinisikan untuk mendapatkan BOOL (blok animasi UIView, misalnya), saat Anda mengkompilasi untuk iOS 32 bit (iPhone 5C ...). Saya menggunakan C ++ bool di mana-mana dalam kode saya, dan BOOL di API yang didefinisikan dengan BOOL
stephane k.
8

Tipe Objective-C yang harus Anda gunakan adalah BOOL. Tidak ada yang seperti datatype boolean asli, oleh karena itu untuk memastikan bahwa kode dikompilasi pada semua kompiler digunakan BOOL. (Ini didefinisikan dalam Kerangka Apple.

Georg Schölly
sumber
2
Ini tidak sepenuhnya akurat. BOOLdidefinisikan oleh bahasa Objective-C (ada di salah satu objc/*.hheader), bukan oleh kerangka kerja. Juga, ketika mengkompilasi dengan C99 (yang saya pikir adalah default), maka ada tipe Boolean asli, _Bool(atau booljika stdbool.hdisertakan).
dreamlax
5

Yup, BOOL adalah typedef untuk char yang ditandatangani menurut objc.h.

Saya tidak tahu tentang bool. Itu hal C ++, kan? Jika itu didefinisikan sebagai char yang ditandatangani di mana 1 adalah YA / benar dan 0 adalah TIDAK / salah, maka saya membayangkan itu tidak masalah yang mana yang Anda gunakan.

Karena BOOL adalah bagian dari Objective-C, meskipun, mungkin lebih masuk akal untuk menggunakan BOOL untuk kejelasan (pengembang Objective-C lainnya mungkin bingung jika mereka melihat bool sedang digunakan).

Jeff
sumber
6
_Bool didefinisikan dalam C99, dan dalam stdbool.h header standar, bool makro didefinisikan (yang diperluas ke _Bool) dan true / false juga didefinisikan di sini.
Brian Mitchell
4

Perbedaan lain antara bool dan BOOL adalah bahwa mereka tidak mengonversi dengan tepat ke objek yang sama, ketika Anda mengamati kunci-nilai, atau ketika Anda menggunakan metode seperti - [NSObject valueForKey:].

Seperti yang dikatakan semua orang di sini, BOOL adalah char. Dengan demikian, ini dikonversi ke NSNumber yang memegang char. Objek ini tidak bisa dibedakan dari NSNumber yang dibuat dari char biasa seperti 'A' atau '\ 0'. Anda telah benar-benar kehilangan informasi yang awalnya Anda miliki BOOL.

Namun, bool dikonversi menjadi CFBoolean, yang berperilaku sama dengan NSNumber, tetapi yang mempertahankan asal boolean objek.

Saya tidak berpikir bahwa ini adalah argumen dalam debat BOOL vs bool, tetapi ini mungkin menggigit Anda suatu hari.

Secara umum, Anda harus menggunakan BOOL, karena ini adalah jenis yang digunakan di mana saja di API Cocoa / iOS (dirancang sebelum C99 dan jenis bool aslinya).

Gwendal Roué
sumber
2

Jawaban yang diterima telah diedit dan penjelasannya menjadi sedikit salah. Contoh kode telah di-refresh, tetapi teks di bawah ini tetap sama. Anda tidak dapat berasumsi bahwa BOOL adalah char untuk saat ini karena itu tergantung pada arsitektur dan platform. Jadi, jika Anda menjalankan kode Anda pada platform 32bit (misalnya iPhone 5) dan mencetak @encode (BOOL) Anda akan melihat "c". Ini sesuai dengan tipe char . Tetapi jika Anda menjalankan kode Anda di iPhone 5s (64 bit) Anda akan melihat "B". Ini sesuai dengan tipe bool .

ingin tahu
sumber
1

Saya menentang konvensi di sini. Saya tidak suka typedef untuk tipe dasar. Saya pikir ini adalah tipuan yang tidak berguna yang menghilangkan nilai.

  1. Ketika saya melihat tipe dasar di sumber Anda, saya akan langsung memahaminya. Jika itu typedef saya harus mencarinya untuk melihat apa yang sebenarnya saya hadapi.
  2. Ketika porting ke kompiler lain atau menambahkan perpustakaan lain, set typedef mereka mungkin konflik dan menyebabkan masalah yang sulit untuk di-debug. Aku baru saja selesai berurusan dengan ini. Di satu perpustakaan boolean diketikkan ke int, dan di mingw / gcc itu diketikkan ke char.
Jay
sumber
4
Nah ... Anda dapat diharapkan untuk mengetahui tipe standar bahasa Anda (berpikir size_t), dan keduanya bool(C99) dan BOOL(ObjC) termasuk dalam kategori itu. Dan jika kode Anda gagal karena perubahan typedef, itu kode Anda yang harus disalahkan karena Anda tampaknya tidak menangani typedef sebagai hal yang buram tetapi mengandalkan implementasinya pada satu platform. (Tidak perlu malu, itu terjadi, tapi itu bukan kesalahan yang harus disalahkan.)
DevSolar
1
Typedef "standar" tampaknya tidak terlalu standar (misalnya untuk sementara waktu MS tidak mendukung standar posix, dll). Jika Anda tidak menggunakan typedef maka masalah dengan typedef berubah atau berbeda pada kompiler yang berbeda dihilangkan.
Jay
1
-1, typedefs secara umum melayani dua tujuan penting (antara lain): memberikan semantik yang baik dan memberikan beberapa penyesatan. Idealnya Anda tidak perlu tahu tipe dasar yang digunakan typedef, sayangnya sistem ini tidak sempurna dan terkadang Anda harus tahu. Maksud saya adalah: Anda harus mengikuti konvensi karena bahkan mengakui bahwa itu tidak sempurna lebih baik daripada alternatifnya.
João Portela
2
@ Jay: Maaf, saya seharusnya menjelaskan mengapa "penyesatan" ini bagus. Saya akan mencoba memberikan contoh: jika Anda menggunakan boolean yang diketik alih-alih menggunakan int atau char secara langsung, Anda mengizinkan jenis yang berbeda (yang masih berfungsi) untuk digunakan pada setiap platform tanpa melanggar kode Anda [alasan untuk ini bervariasi tetapi kita dapat membayangkan sebuah platform di mana char mungkin tidak selaras dalam memori dan karenanya lebih lambat sehingga int dapat digunakan untuk boolean sebagai gantinya].
João Portela
2
@ Jay: Dengan "semantik yang baik" Maksud saya ketika Anda mendeklarasikan boolean Anda BOOL varnamealih-alih char varnamelebih jelas bahwa dua nilai yang valid untuk variabel tersebut adalah true/ YESatau false/ NO.
João Portela
1

Seperti yang disebutkan di atas BOOLbisa menjadi unsigned chartipe tergantung pada arsitektur Anda, sementara booltipe int. Eksperimen sederhana akan menunjukkan perbedaan mengapa BOOL dan bool dapat berperilaku berbeda:

bool ansicBool = 64;
if(ansicBool != true) printf("This will not print\n");

printf("Any given vlaue other than 0 to ansicBool is evaluated to %i\n", ansicBool);

BOOL objcBOOL = 64;
if(objcBOOL != YES) printf("This might print depnding on your architecture\n");

printf("BOOL will keep whatever value you assign it: %i\n", objcBOOL);

if(!objcBOOL) printf("This will not print\n");

printf("! operator will zero objcBOOL %i\n", !objcBOOL);

if(!!objcBOOL) printf("!! will evaluate objcBOOL value to %i\n", !!objcBOOL);

Yang mengejutkan Anda if(objcBOOL != YES)akan mengevaluasi ke 1 oleh kompiler, karena YESsebenarnya adalah kode karakter 1, dan di mata kompiler, kode karakter 64 tentu saja tidak sama dengan kode karakter 1 sehingga pernyataan if akan dievaluasi YES/true/1dan baris berikut akan Lari. Namun karena tidak ada booltipe nol yang selalu mengevaluasi ke nilai integer 1, masalah di atas tidak akan memengaruhi kode Anda. Di bawah ini adalah beberapa tips yang baik jika Anda ingin menggunakan Objective-C BOOLtipe vs ANSI C booltipe:

  • Selalu berikan YESatau NOnilai dan tidak ada yang lain.
  • Konversi BOOLjenis dengan menggunakan !!operator ganda bukan untuk menghindari hasil yang tidak terduga.
  • Saat memeriksa YESpenggunaan if(!myBool) instead of if(myBool != YES), jauh lebih bersih untuk menggunakan !operator yang tidak dan memberikan hasil yang diharapkan.
ilgaar
sumber
1

Perlu diketahui juga perbedaan casting, terutama ketika bekerja dengan bitmask, karena casting ke char yang ditandatangani:

bool a = 0x0100;
a == true;  // expression true

BOOL b = 0x0100;
b == false; // expression true on !((TARGET_OS_IPHONE && __LP64__) || TARGET_OS_WATCH), e.g. MacOS
b == true;  // expression true on (TARGET_OS_IPHONE && __LP64__) || TARGET_OS_WATCH

Jika BOOL adalah char yang ditandatangani dan bukan bool, cast 0x0100 ke BOOL cukup menjatuhkan bit yang diset, dan nilai yang dihasilkan adalah 0.

michaf
sumber