ios

iOS中BOOL跟bool的区别

2019-02-14  本文已影响1人  Sunli_

起因

在技术群里发现有人在问

    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上搜到了,在这里整理一下,有需要的朋友可以看原文

    // __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无符号)

#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
/* 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

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时。

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类型进行了隐式处理。

我们该怎么做

参考链接

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

上一篇下一篇

猜你喜欢

热点阅读