Objective-C:BOOL vs bool
Posted
技术标签:
【中文标题】Objective-C:BOOL vs bool【英文标题】:Objective-C : BOOL vs bool 【发布时间】:2010-10-07 04:16:22 【问题描述】:我看到了“新类型”BOOL
(YES
,NO
)。
我读到这种类型几乎就像一个字符。
为了测试我做了:
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 等)使用 C99bool
。所有的 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.x
,ios
版本是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 上 BOOL
与 bool
完全相同,而在所有其他设备(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
类型,具体取决于您的架构,而 bool
是 int
类型。一个简单的实验将展示 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
类型,以下是一些很好的提示:
YES
或 NO
值,仅此而已。
使用 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 变量作为参数传递?