原文地址:蘋果梨的博客html
嗯,昨天給本身挖了個坑,仍是早填坑早完事兒,因此今天有了這篇:bash
朋友,ObjC 的 BOOL 類型瞭解一下?函數
可能有人告訴你 BOOL 是 signed char
類型的。放在之前,這個答案是對的,可是放在如今就不徹底對了。接下來我來給你們一點點解釋其中的細節。ui
當前個人 Xcode 版本是 9.3.1,BOOL 的定義是這樣的(有適當刪減):spa
#if TARGET_OS_OSX || (TARGET_OS_IOS && !__LP64__ && !__ARM_ARCH_7K)
# define OBJC_BOOL_IS_BOOL 0
#else
# define OBJC_BOOL_IS_BOOL 1
#endif
#if OBJC_BOOL_IS_BOOL
typedef bool BOOL;
#else
# define OBJC_BOOL_IS_CHAR 1
typedef signed char BOOL;
#endif
複製代碼
做爲 iPhone 開發者(🙄),能夠近似的理解爲在 64-bit 設備上 BOOL 實際是 bool
類型,在 32-bit 設備上 BOOL 的實際類型是 signed char
。翻譯
那麼 YES
/ NO
又分別是什麼值呢?咱們看一下具體的定義:code
#if __has_feature(objc_bool)
#define YES __objc_yes
#define NO __objc_no
#else
#define YES ((BOOL)1)
#define NO ((BOOL)0)
#endif
複製代碼
這裏要先看一下 __objc_yes
和 __objc_no
是什麼值,咱們在 LLVM 的文檔中能夠獲得答案:cdn
The compiler implicitly converts __objc_yes and __objc_no to (BOOL)1 and (BOOL)0. The keywords are used to disambiguate BOOL and integer literals.
複製代碼
__objc_yes
和 __objc_no
其實就是 (BOOL)1
和 (BOOL)0
,這麼寫的緣由就是爲了消除 BOOL 和整型數的歧義而已。htm
(BOOL)1
和 (BOOL)0
這個你們應該也都能很容易理解了,其實就是把 1 和 0 強轉成了 BOOL 對應的實際類型。blog
因此綜上所述爲了類型的正確對應,在給 BOOL 類型設值時要用 YES
/ NO
。
最先的標準 C 語言裏是沒有 bool
類型的,在 2000 年的 C99 標準裏,新增了 _Bool
保留字,而且在 stdbool.h
裏定義了 true
和 false
。stdbool.h
的內容能夠參照這裏:
#define bool _Bool
#define true 1
#define false 0
複製代碼
這裏只截取了標準 C 語言狀況下的定義(C++ 是自帶 bool 和 true、false 的)。能夠看到這裏只是定義了它們的值,可是卻沒有保證它們的類型,就是說 true
/ false
其實能夠應用在各類數據類型上。
有些人還提到 TRUE
/ FALSE
這兩個宏定義,它們其實不是某個標準定義裏的內容,通常是早年沒有標準定義時自定義出來替代 true
/ false
使用的,大部分狀況下他們的定義和 true
/ false
一致。
咱們能夠寫一段代碼來驗證下:
BOOL a = TRUE;
a = true;
a = YES;
複製代碼
使用 Xcode 的菜單進行預處理,展開宏定義:
而後咱們就能夠獲得展開後的結果:
BOOL a = 1;
a = 1;
a = __objc_yes;
複製代碼
能夠看到 ObjC 是本身定義了 BOOL 的類型,而後定義了對應要使用的值 YES
/ NO
,理所固然的第一個緣由是咱們要按照標準來。
另外一方面,既然 ObjC 的 BOOL 使用的不是標準 C 的定義,那麼之後這個定義可能還會修改。雖說機率很低,可是畢竟從上面的代碼看就經歷了 signed char
到 bool
的一次修改不是麼?爲了不這種風險,建議仍是要使用 YES
/ NO
。
在某些狀況下,類型不匹配會致使 warning,而 YES
/ NO
是帶類型的,能夠保證類型正確,因此建議要用 YES
/ NO
。
由於 BOOL 類型在不一樣設備有不一樣的表現,因此有一些地方咱們要注意。
在 BOOL 爲 bool
類型的時候,只有真假兩個值,實際上是能夠寫 "== YES" 和 "!= YES" 的。咱們先舉個例子:
BOOL a = 2;
if (a) {
NSLog(@"a is YES");
} else {
NSLog(@"a is NO");
}
if (a == YES) {
NSLog(@"a == YES");
} else {
NSLog(@"a != YES");
}
複製代碼
在 64-bit 設備咱們將獲得結果:
a is YES
a == YES
複製代碼
看上去沒什麼毛病,完美!
可是在 32-bit 設備咱們將獲得結果:
a is YES
a != YES
複製代碼
這是爲何呢?由於在 32-bit 設備上 BOOL 是 signed char
類型的。ObjC 對數值類型作 (a)
這種真假判斷時爲 0 則假、非 0 則真,因此咱們能夠獲得 a is YES
這種結果。可是對數值類型作 (a == YES)
這種判斷時邏輯是什麼樣的,想必不用我說你們也猜到了,代碼翻譯出來就是相似這樣的:
signed char a = 2;
if (a == (signed char)1) {
NSLog(@"a == YES");
} else {
NSLog(@"a != YES");
}
複製代碼
咱們固然只能獲得 a != YES
這樣的結果。
一樣在 64-bit 的設備上,也就是 bool
類型上不會有這個問題,可是在 signed char
類型上就會有這個問題。咱們先看代碼:
int a = 256;
if (a) {
NSLog(@"a is YES");
} else {
NSLog(@"a is NO");
}
BOOL b = a;
if (b) {
NSLog(@"b is YES");
} else {
NSLog(@"b is NO");
}
複製代碼
在 32-bit 設備上輸出結果:
a is YES
b is NO
複製代碼
是否是有點魔幻?可是緣由也驚人的簡單:
a
的二進制值爲 00000000 00000000 00000001 00000000signed char
類型的 b
時丟失了高位b
的二進制值爲 00000000因此千萬不要作這樣的蠢事,更常見的例子是一個 C 函數(十分直觀):
// 正確的用法
bool isDifferent(int a, int b) {
return a - b;
}
// 錯誤的用法
signed char isDifferent(int a, int b) {
return a - b;
}
複製代碼
但願今天的介紹可讓你更深刻的瞭解 ObjC 的 BOOL 類型,當心點不要在代碼裏埋出大 bug 哦。