我曾经认为在64位Obj-C运行时BOOL实际上是_Bool而且它是一个真正的类型所以这样编写是安全的:
BOOL a = YES;
BOOL b = NO;
if (a != b) {...}
它的工作似乎很好但是今天我发现了一个问题,当我使用这样的位字段结构时:
typedef struct
{
BOOL flag1 : 1;
} FlagsType;
FlagsType f;
f.flag1 = YES;
BOOL b = YES;
if (f.flag1 != b)
{
// DOES GET HERE!!!
}
似乎从位字段返回的BOOL等于-1而常规BOOL为1,并且它们不相等!!!
请注意,我知道当一个任意整数被强制转换为BOOL时会出现这种情况,因此变成一个“奇怪”的BOOL,这是不可安全比较的。
但是在这种情况下,flag1字段和b都被声明为BOOL并且从不投射。问题是什么?这是编译器错误吗?
更大的问题是,比较BOOL是否真的安全,还是应该编写XORing辅助函数? (这将是一件苦差事,因为布尔比较无处不在......)
答案 0 :(得分:3)
我不重复使用C布尔类型解决了BOOL
可能遇到的问题。这是真的 - 特别是在这里,你可以在下面看到 - ,但大多数问题是由于错误存储到布尔(C)对象造成的。但在这种情况下,_Bool
或unsigned
(int
)似乎是唯一可行的解决方案。 (除了带有额外代码的解决方案。)有一个原因:
我找不到Objective-C中BOOL
的新行为的精确文档,但是您发现的行为是错误和错误之间的行为。我希望最新的行为类似于_Bool
。在你的情况下,这不是真的。 (感谢您找到了!)也许这是为了向后兼容。讲述全文:
在C中,int
类型的对象是signed int
。 (这与char
不同。对于此类型,signedess是实现定义的。)
- int,signed或signed int
ISO / IEC 9899:TC3,6.7.2-2
每个逗号分隔的集合指定相同的类型,[...]
ISO / IEC 9899:TC3,6.7.2-5
但由于历史原因,有一个奇怪的例外:
如果int
对象是位字段,则它是实现定义的,无论是signed int
还是unsigned int
。 (可能这是因为过去的某些CPU无法自动扩展部分字节整数的符号。因此,使用无符号整数更容易,因为将顶部位置零是足够的。)
在clang上,默认值为signed int
。因此,根据全宽整数int
总是表示签名整数,即使它只有一位。 int member : 1
只能存储0
和-1
! (因此,使用int
无法解决问题。)
每个逗号分隔的集都指定相同的类型,除了对于位字段,它是实现定义的,指定符int是指定与signed int相同的类型还是与unsigned int相同的类型。
ISO / IEC 9899:TC3,6.7.2-5
C标准说布尔位字段是整数类型,因此参与了位字段的奇怪整数签名规则:
位字段被解释为由指定位数组成的有符号或无符号整数类型。
ISO / IEC 9899:TC3,6.7.2.1-9
这是您找到的行为。因为这对于1位布尔类型没有意义,所以C标准明确表示将1存储到布尔位域必须在每种情况下比较等于1:
如果将值0或1存储到_Bool类型的非零宽度位字段中,则位字段的值应等于存储的值。
ISO / IEC 9899:TC3,6.7.2.1-9
这导致了一种奇怪的情况,即一个实现可以将宽度为1的布尔值实现为{0,-1},但必须满足1 == -1。大。
所以,短篇小说:BOOL
的行为类似于整数位字段(符合标准),但不参与_Bool
的额外要求。
我认为这是因为遗留代码。 (人们可以期待过去的-1。)