ObjC的BOOL为何要用YES、NO而不建议用true、false?

原文地址:苹果梨的博客html

嗯,昨天给本身挖了个坑,仍是早填坑早完事儿,因此今天有了这篇:bash

朋友,ObjC 的 BOOL 类型了解一下?函数

可能有人告诉你 BOOL 是 signed char 类型的。放在之前,这个答案是对的,可是放在如今就不彻底对了。接下来我来给你们一点点解释其中的细节。ui

ObjC 的 BOOL 究竟是什么类型?

当前个人 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 是什么?

那么 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

true / false 是什么?

最先的标准 C 语言里是没有 bool 类型的,在 2000 年的 C99 标准里,新增了 _Bool 保留字,而且在 stdbool.h 里定义了 truefalsestdbool.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 的菜单进行预处理,展开宏定义:

16-A

而后咱们就能够获得展开后的结果:

BOOL a = 1;
a = 1;
a = __objc_yes;
复制代码

为何要对 BOOL 用 YES / NO 而不是 true / false?

能够看到 ObjC 是本身定义了 BOOL 的类型,而后定义了对应要使用的值 YES / NO,理所固然的第一个缘由是咱们要按照标准来。

另外一方面,既然 ObjC 的 BOOL 使用的不是标准 C 的定义,那么之后这个定义可能还会修改。虽说几率很低,可是毕竟从上面的代码看就经历了 signed charbool 的一次修改不是么?为了不这种风险,建议仍是要使用 YES / NO

在某些状况下,类型不匹配会致使 warning,而 YES / NO 是带类型的,能够保证类型正确,因此建议要用 YES / NO

使用 BOOL 类型的注意点

由于 BOOL 类型在不一样设备有不一样的表现,因此有一些地方咱们要注意。

不要手贱写 "== YES" 和 "!= YES"

在 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 这样的结果。

避免把超过 8-bit 的数据强转成 BOOL

一样在 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 00000000
  • 转换为 signed 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 哦。

相关文章
相关标签/搜索