Objective-C:BOOL vs bool

Objective-C : BOOL vs bool

我看到了"新类型"BOOL(YESNO)。

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

为了测试,我做了:

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

很高兴看到两个日志都显示"1"(有时在C ++中bool是一个int,其sizeof是4)

所以我只是想知道bool类型是否存在某些问题?

我可以在不失速度的情况下使用bool(看似有效)吗?


objc.h中的定义:

1
2
3
4
5
6
7
8
9
10
#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是一个char。您可以使用(C99)BOOL类型,但所有Apple的Objective-C框架和大多数Objective-C / Cocoa代码都使用BOOL,因此如果仅使用BOOL更改typedef,您将免于头痛。


如上所述,BOOL是一个签名字符。 bool - 来自C99标准(int)的类型。

BOOL - 是/否。 bool - 真/假。

见例子:

1
2
3
4
5
6
7
8
9
10
11
bool b1 = 2;
if (b1) printf("REAL b1
"
);
if (b1 != true) printf("NOT REAL b1
"
);

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

结果是

REAL b1
REAL b2
NOT REAL b2

注意bool!= BOOL。以下结果仅为ONCE AGAIN - REAL b2

1
2
3
4
5
b2 = b1;
if (b2) printf("ONCE AGAIN - REAL b2
"
);
if (b2 != true) printf("ONCE AGAIN - NOT REAL b2
"
);

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

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

所以,在我们的案例中:

1
2
3
4
5
BOOL b22 = b1 ? 2 : NO;
if (b22)    printf("ONCE AGAIN MORE - REAL b22
"
);
if (b22 != YES) printf("ONCE AGAIN MORE- NOT REAL b22
"
);

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


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

1
2
3
4
5
6
7
8
9
10
/// 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,甚至无法被编译器覆盖flag -funsigned-char

它还意味着此示例代码将在不同平台上以不同方式运行(我自己测试):

1
2
3
4
5
6
7
int myValue = 256;
BOOL myBool = myValue;
if (myBool) {
    printf("i'm 64-bit iOS");
} else {
    printf("i'm 32-bit iOS");
}

BTW从不将array.count之类的内容分配给BOOL变量,因为大约0.4%的可能值将为负数。


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


根据objc.h,Yup,BOOL是签名字符的typedef.

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

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


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

正如大家在这里所说,BOOL是char。因此,它被转换为持有char的NSNumber。此对象与从常规字符"A"或" 0"创建的NSNumber无法区分。您完全丢失了原本拥有BOOL的信息。

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

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

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


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


如上所述,BOOL可以是unsigned char类型,具体取决于您的体系结构,而BOOL的类型为int。一个简单的实验将显示BOOL和bool可以表现不同的原因:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
bool ansicBool = 64;
if(ansicBool != true) printf("This will not print
"
);

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

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

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

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

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

if(!!objcBOOL) printf("!! will evaluate objcBOOL value to %i
"
, !!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 !运算符并提供预期结果会更清晰。

我在这里反对惯例。我不喜欢typedef的基类型。我认为这是一种无用的间接方式,可以消除价值。

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

  • 此外,请注意转换中的差异,特别是在使用位掩码时,由于转换为signed char:

    1
    2
    3
    4
    5
    6
    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是带符号的char而不是bool,则将0x0100转换为BOOL只会丢弃设置位,结果值为0。