美文网首页ios
iOS中BOOL跟bool的区别

iOS中BOOL跟bool的区别

作者: Sunli_ | 来源:发表于2019-02-14 14:52 被阅读1次

起因

在技术群里发现有人在问

    BOOL a = 8960;
    bool b = 8960;
    
    if (a) {
        NSLog(@"a yes");
    } else {
        NSLog(@"a no");
    }
    if (b) {
        NSLog(@"b yes");
    } else {
        NSLog(@"b no");
    }

这一段会输出什么,问这个的原因是他看到博客上都说是输出a no b yes,但是自己测了不是这样。
先说结论:在32位系统上输出a no b yes,在64位系统上输出a yes b yes(本文所有关于操作系统的信息都是基于iPhone上,即iOS)。

BOOL和bool到底是什么

Stack Overflow上搜到了,在这里整理一下,有需要的朋友可以看原文

  • 首先我们来看一下OC中对于BOOL的定义,在objc.h头文件中,可以通过import <objc/objc.h>进入(适当删减)
    // __OBJC_BOOL_IS_BOOL not set.
#   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; 
    // BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C" 
    // even if -funsigned-char is used.
#endif

从这里面可以看出,如果设备是64位的iPhone且架构为ARMv7k则定义BOOLbool类型。如果设备不满足这些条件,那么就定义BOOLsigned char有符号字符型(signed有符号unsigned无符号)

  • 下面是BOOL类型中YESNO的定义
#if __has_feature(objc_bool)
#define YES __objc_yes
#define NO  __objc_no
#else
#define YES ((BOOL)1)
#define NO  ((BOOL)0)
#endif

__has_feature (objc_bool)意思是判断是否有objc_bool这个特性

if (__has_feature(objc_bool)) {
    NSLog(@"yes");
} else {
    NSLog(@"NO");
}

经测试在32位和64iPhone上都打印为yes,那么对于YESNO,在iOS里其实就是__objc_yes __objc_no,在LLVM文档里写了对了__objc_yes __objc_no的定义。


以前的BOOL类型就是signed charYESNO(BOOL)1(BOOL)0的宏定义,后为了支持@(YES)@(NO)的表达方式,现在就将YESNO定义成了__objc_yes __objc_no(这两个都是关键字),用来消除BOOL类型和整形之间的歧义。
打印一下__objc_yes __objc_no结果为1和0,当使用%@占位符打印的时候,会报警告,后面的提示跟上面所说的不同位数下BOOL的类型相符。
32位
64位
那么这个__objc_yes32位下是signed char 164位下是bool 1
  • 那么bool类型又是什么呢,首先我们在stdbool.h找到bool的定义
/* Don't define bool, true, and false in C++, except as a GNU extension. */
#ifndef __cplusplus
#define bool _Bool
#define true 1
#define false 0
#elif defined(__GNUC__) && !defined(__STRICT_ANSI__)
/* Define _Bool as a GNU extension. */
#define _Bool bool
#if __cplusplus < 201103L
/* For C++98, define bool, false, true as a GNU extension. */
#define bool  bool
#define false false
#define true  true
#endif
#endif

#define __bool_true_false_are_defined 1
  • __cplusplus这个宏是代表编译器将文件按照C/C++语法来解释。

  • 当前程序按C语法来解释的话,定义bool_Bool(stdbool.h头文件是在C99中新增的,为了解决C中没有bool类型这个问题,并且和C++兼容),_BoolC99中新增的关键字,只有0 1两个值,只占1个字节。这里还定义了true 1false 0,这就相当于将_Bool关键字转为了bool类型,且值为truefalse

  • 当前程序按C++语法来解释的话(C++有bool类型,占1个字节),那么定义_Boolbool类型。后面这几句#define x x是因为在C99 standard中提到了

The header shall define the following macros: bool, true, false, __bool_true_false_are_defined.
An application may undefine and then possibly redefine the macros bool, true, and false.
头文件应定义以下宏:bool、true、false、__bool_true_false_are_defined。
应用程序可能没有定义这些宏,然后重新定义bool、true和false。

这里#define x x还有一个用处是可以在其他地方使用

#ifdef bool
  some code here
#endif

认清BOOL

我们可以发现,不管是在C(C99之后)还是在C++中,bool类型都只有两个值,0/1 (赋值的时候如果不等于0,则为1),且都只占一个字节

那么:

  1. 64位操作系统上或处理器架构为ARMv7kBOOLbool,取值为0或1,如
BOOL a = ?; 
// 等价于
bool a = ?;
// 即只有当?为0的情况下,a才NO,其余情况都等于YES

上文中的BOOL a = 8960a就等于YES

  1. 32位操作系统上,BOOL类型为signed char,占一个字节,取值范围为-128~127

问题在哪

32位操作系统上,BOOLsigner char时。

  • 在赋值的过程中,如果赋值的对象字节数超过了1个字节,那么只会取到低8位的值。
    如8960,转化为二进制为
    0010 0011 0000 0000
    这时候BOOL b = 8960 等同于 BOOL b = 0000 0000,高位会全部丢失,即b = 0,这时候就会出现BOOL b = 8960 b = NO的问题。

  • 除了赋值的时候可能有问题,比较的时候也可能有问题,如

BOOL c = 2;
if (c == YES) {
    NSLog(@"c YES");
} else {
    NSLog(@"c NO");
}
if (c) {
    NSLog(@"c == %d", c);
} else {
    NSLog(@"else c == %d", c);
}
NSLog(@"@(c) = %@", @(c));

输出c NOc == 2@(c) = 1。在上文中已经说了YES这时候等于signed char 1,那么很显然,signed char 2 != signed char 1,即c != YES,将其转为对象后,输出1,猜测应该是NSNumberBOOL类型进行了隐式处理。

我们该怎么做

  • 在条件判断语句中,不要直接使用x == YES,或x != YES这种写法

  • 避免将大于一个字节的值赋值给BOOL类型的变量,如BOOL a = 8960

  • 使用bool类型

参考链接

ObjC的BOOL为什么要用YES、NO而不建议用true、false
解释一下为啥负数的取值范围比整数要多一个
Objc 中 “== YES” 的愚蠢行为有多可怕
BOOL with 64-bit on iOS
_Bool data type of C99
Why does clang's stdbool.h contain #define false false
Utility of macros for enum

本文中32位的测试机为iPhone 5C

相关文章

网友评论

    本文标题:iOS中BOOL跟bool的区别

    本文链接:https://www.haomeiwen.com/subject/lptucqtx.html