Objective-C:BOOL vs bool

Posted

技术标签:

【中文标题】Objective-C:BOOL vs bool【英文标题】:Objective-C : BOOL vs bool 【发布时间】:2010-10-07 04:16:22 【问题描述】:

我看到了“新类型”BOOLYESNO)。

我读到这种类型几乎就像一个字符。

为了测试我做了:

NSLog(@"Size of BOOL %d", sizeof(BOOL));
NSLog(@"Size of bool %d", sizeof(bool));

很高兴看到两个日志都显示“1”(有时在 C++ 中 bool 是一个 int 而它的 sizeof 是 4)

所以我只是想知道 bool 类型是否有问题?

我可以只使用 bool(这似乎有效)而不会降低速度吗?

【问题讨论】:

【参考方案1】:

来自objc.h中的定义:

#if (TARGET_OS_IPHONE && __LP64__)  ||  TARGET_OS_WATCH
typedef bool BOOL;
#else
typedef signed char BOOL; 
// BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C" 
// even if -funsigned-char is used.
#endif

#define YES ((BOOL)1)
#define NO  ((BOOL)0)

所以,是的,您可以假设 BOOL 是一个字符。您可以使用 (C99) bool 类型,但所有 Apple 的 Objective-C 框架和大多数 Objective-C/Cocoa 代码都使用 BOOL,因此如果 typedef 发生变化,只需使用 BOOL,您就不会感到头疼。

【讨论】:

“Apple 的所有框架”——不正确。看一下 CGGeometry.h,具体是:CG_INLINE bool __CGPointEqualToPoint(CGPoint point1, CGPoint point2) return point1.x == point2.x && point1.y == point2.y; @Elliot 你是对的。许多 C 框架(CoreFoundation、CoreGraphics 等)使用 C99 bool。所有的 Objective-C 框架都使用BOOL @Cœur 您已经编辑了 BOOL 代码示例的定义,但下面的文本保持不变。这有点令人困惑并且不正确。看我的回答。 了解不同的行为,请看下面。 NSInteger progressTime = 2;//any value NSInteger totalTime = 1;//any value BOOL success = (progressTime>=totalTime)//它总是给出NO 但是一旦我收到(progressTime>=totalTime) 值到bool 类型success 它返回正确的结果。我不明白这种行为。我正在使用Xcode 7.xios 版本是8.x。 @BarryWark【参考方案2】:

如上所述,BOOL 是有符号字符。 bool - 来自 C99 标准 (int) 的类型。

BOOL - 是/否。布尔 - 真/假。

查看示例:

bool b1 = 2;
if (b1) printf("REAL b1 \n");
if (b1 != true) printf("NOT REAL b1 \n");

BOOL b2 = 2;
if (b2) printf("REAL b2 \n");
if (b2 != YES) printf("NOT REAL b2 \n");

结果是

真实的 b1 真正的 b2 不是真的 b2

注意 bool != BOOL。下面的结果只是 ONCE AGAIN - REAL b2

b2 = b1;
if (b2) printf("ONCE AGAIN - REAL b2 \n");
if (b2 != true) printf("ONCE AGAIN - NOT REAL b2 \n");

如果你想将 bool 转换为 BOOL,你应该使用下一个代码

BOOL b22 = b1 ? YES : NO; //and back - bool b11 = b2 ? true : false;

所以,在我们的例子中:

BOOL b22 = b1 ? 2 : NO;
if (b22)    printf("ONCE AGAIN MORE - REAL b22 \n");
if (b22 != YES) printf("ONCE AGAIN MORE- NOT REAL b22 \n");

所以.. 我们现在得到了什么? :-)

【讨论】:

您可以使用!!b1,而不是使用三元运算符。在它们之间进行转换 'NOT REAL b2' 没有打印在我的 iPhone SE 模拟器上。【参考方案3】:

在撰写本文时,这是 objc.h 的最新版本:

/// Type to represent a boolean value.
#if (TARGET_OS_IPHONE && __LP64__)  ||  TARGET_OS_WATCH
#define OBJC_BOOL_IS_BOOL 1
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 位 iOS 设备和 WatchOS 上 BOOLbool 完全相同,而在所有其他设备(OS X、32 位 iOS)上它是 signed char 甚至不能被编译器标志-funsigned-char覆盖

这也意味着这个示例代码在不同的平台上会以不同的方式运行(自己测试过):

int myValue = 256;
BOOL myBool = myValue;
if (myBool) 
    printf("i'm 64-bit iOS");
 else 
    printf("i'm 32-bit iOS");

顺便说一句,永远不要将 array.count 之类的东西分配给 BOOL 变量,因为大约 0.4% 的可能值将是负数。

【讨论】:

当您为 iOS 32 位 (iPhone 5C. ..)。我在代码中随处使用 C++ bool,在使用 BOOL 定义的 API 中使用 BOOL【参考方案4】:

你应该使用的 Objective-C 类型是BOOL。没有什么能比得上原生布尔数据类型,因此要确保代码在所有编译器上编译都使用BOOL。 (它在 Apple-Frameworks 中定义。

【讨论】:

这并不完全准确。 BOOL 由 Objective-C 语言定义(它位于 objc/*.h 标头之一中),而不是由框架定义。此外,当使用 C99(我认为这是默认值)编译时,会有一个原生布尔类型 _Bool(如果包含 stdbool.h,则为 bool)。【参考方案5】:

是的,BOOL 是根据 objc.h 的有符号字符的 typedef。

不过,我不知道 bool。那是 C++ 的东西,对吧?如果它被定义为一个有符号的字符,其中 1 是 YES/true 而 0 是 NO/false,那么我想你使用哪个并不重要。

由于 BOOL 是 Objective-C 的一部分,但为了清楚起见,使用 BOOL 可能更有意义(如果其他 Objective-C 开发人员看到使用的布尔值可能会感到困惑)。

【讨论】:

_Bool 是在 C99 中定义的,在标准头文件 stdbool.h 中,定义了宏 bool(扩展为 _Bool),这里也定义了 true/false。【参考方案6】:

bool 和 BOOL 之间的另一个区别是,当您进行键值观察或使用 -[NSObject valueForKey:] 之类的方法时,它们不会完全转换为相同类型的对象。

正如大家在这里所说的,BOOL 是字符。因此,它被转换为一个 NSNumber 持有一个字符。该对象与从常规字符(如“A”或“\0”)创建的 NSNumber 无法区分。您完全丢失了您最初拥有 BOOL 的信息。

但是,bool 被转换为 CFBoolean,其行为与 NSNumber 相同,但保留了对象的布尔原点。

我不认为这是 BOOL 与 bool 辩论中的争论,但这可能有一天会咬到你。

一般来说,您应该使用 BOOL,因为这是 Cocoa/iOS API 中到处使用的类型(在 C99 及其原生 bool 类型之前设计)。

【讨论】:

【参考方案7】:

已接受的答案已被编辑,其解释变得有点不正确。代码示例已刷新,但下面的文本保持不变。你现在不能假设 BOOL 是一个字符,因为它取决于架构和平台。 因此,如果您在 32 位平台(例如 iPhone 5)上运行代码并打印 @encode(BOOL),您将看到“c”。它对应于char type。 但是,如果您在 iPhone 5s(64 位)上运行代码,您将看到“B”。它对应于bool type。

【讨论】:

【参考方案8】:

我在这里违反惯例。我不喜欢 typedef 的基本类型。我认为这是消除价值的无用间接。

    当我在您的源代码中看到基本类型时,我会立即理解它。如果它是 typedef,我必须查看它以了解我真正处理的是什么。 当移植到另一个编译器或添加另一个库时,它们的 typedef 集可能会发生冲突并导致难以调试的问题。事实上,我刚刚处理完这个问题。在一个库中,布尔值被 typedef 为 int,而在 mingw/gcc 中,它被 typedef 为 char。

【讨论】:

嗯……你可以知道你的语言的标准类型定义(想想size_t),以及bool(C99)和BOOL (ObjC)属于这一类。如果您的代码由于 typedef 的更改而失败,则应归咎于您的代码,因为您显然没有将 typedef 视为不透明的东西,而是依赖于它在一个平台上的实现。 (没什么可羞耻的,它确实发生了,但这不是 typedef 的责任。) “标准”类型定义似乎不是很标准(例如,有一段时间 MS 不支持 posix 标准等)。如果你不使用 typedefs,那么 typedefs 在不同编译器上改变或不同的问题就会被消除。 -1,typedef 通常有两个重要目的(除其他外):提供良好的语义和提供一些误导。理想情况下,您不需要知道 typedef 所指的基本类型,不幸的是,这个系统并不完美,有时您必须知道。我的观点是:你应该遵守约定,因为即使承认它并不完美,它也比替代方案更好。 @Jay:对不起,我应该解释一下为什么这个“误导”是好的。我将尝试提供一个示例:如果您使用 typedef'd boolean 而不是直接使用 int 或 char,则您允许在每个平台上使用不同的类型(仍然有效)而不会破坏您的代码 [原因这会有所不同,但我们可以想象一个平台,其中 char 可能在内存中未对齐,因此速度较慢,因此可以将 int 用于布尔值]。 @Jay:“良好的语义”是指当您声明布尔值 BOOL varname 而不是 char varname 时,更明显的是该变量的两个有效值是 true/@ 987654327@或false/NO.【参考方案9】:

如上所述,BOOL 可能是 unsigned char 类型,具体取决于您的架构,而 boolint 类型。一个简单的实验将展示 BOOL 和 bool 行为不同的原因:

bool ansicBool = 64;
if(ansicBool != true) printf("This will not print\n");

printf("Any given vlaue other than 0 to ansicBool is evaluated to %i\n", ansicBool);

BOOL objcBOOL = 64;
if(objcBOOL != YES) printf("This might print depnding on your architecture\n");

printf("BOOL will keep whatever value you assign it: %i\n", objcBOOL);

if(!objcBOOL) printf("This will not print\n");

printf("! operator will zero objcBOOL %i\n", !objcBOOL);

if(!!objcBOOL) printf("!! will evaluate objcBOOL value to %i\n", !!objcBOOL);

令你惊讶的是if(objcBOOL != YES) 会被编译器评估为 1,因为YES 实际上是字符代码 1,而在编译器的眼中,字符代码 64 当然是 不等于 到字符代码 1 因此 if 语句将评估为 YES/true/1 并且以下行将运行。 但是,由于非零 bool 类型始终计算为整数值 1,因此上述问题不会影响您的代码。如果您想使用 Objective-C BOOL 类型与 ANSI C bool 类型,以下是一些很好的提示:

始终指定 YESNO 值,仅此而已。 使用 double not !! 运算符转换 BOOL 类型以避免意外结果。 在检查YES 时使用if(!myBool) instead of if(myBool != YES),使用not ! 运算符会更简洁,并给出预期的结果。

【讨论】:

【参考方案10】:

另外,请注意转换的差异,尤其是在使用位掩码时,由于转换为签名字符:

bool a = 0x0100;
a == true;  // expression true

BOOL b = 0x0100;
b == false; // expression true on !((TARGET_OS_IPHONE && __LP64__) || TARGET_OS_WATCH), e.g. MacOS
b == true;  // expression true on (TARGET_OS_IPHONE && __LP64__) || TARGET_OS_WATCH

如果 BOOL 是有符号字符而不是布尔值,则将 0x0100 转换为 BOOL 只会删除设置位,结果值为 0。

【讨论】:

以上是关于Objective-C:BOOL vs bool的主要内容,如果未能解决你的问题,请参考以下文章

在 Swift 中,Objective-C BOOL 被推断为 `()` 而不是 Bool

如何在 Objective-C 中将 BOOL 变量作为参数传递?

在 Objective-C 中循环 BOOL

如何在 Objective-C 中懒惰地设置 BOOL 属性

Prologish Boolos 好奇推理的计算机推理

从 Objective-C 中的 ColdFusion 布尔返回类型获取 BOOL 的更好方法?