iOS中BOOL跟bool的区别

起因

在技术群里发现有人在问

    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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,678评论 0 9
  • 0 前言 5月8日提交的代码在服务端编译出现了错误,而本机编译过程中没有任何问题。定位到错误日志,发现是因为错把函...
    xohozu阅读 10,213评论 2 6
  • 为啥要深挖这玩意 你每天都在用BOOL吧?那我就来问一道题:请问BOOL是非0即真吗? 如果不是百分百确定的,请往...
    从来吃不胖阅读 3,054评论 3 50
  • 1.解决问题:夏日虽多彩,皮肤优喜白,301面膜用白帮你渡过多彩夏日 2.防备问题:风吹日晒,皮肤已亡,岁月在严重...
    闲云野鹤_5eb0阅读 300评论 3 1
  • 纵然 已天各一方 想情谊不曾淡忘 (在这两地穿梭 早已忘却距离) 少年回忆着 那个女孩 (愿女孩一如既往 开心、...
    唯天V阅读 126评论 0 1