原文地址:苹果梨的博客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 哦。