美文网首页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