[Objective-C++]为什么在64位中允许将对象分配给BOOL类型变量,但在32位中不允许

[Objective-C++]为什么在64位中允许将对象分配给BOOL类型变量,但在32位中不允许,objective-c,c++11,32bit-64bit,objective-c++,Objective C,C++11,32bit 64bit,Objective C++,ViewController.mm中的以下代码将在64位环境中编译成功,而不会出现任何警告或错误 - (void)viewDidLoad { [super viewDidLoad]; BOOL var = [[NSUserDefaults standardUserDefaults] objectForKey:@"foo"]; NSLog(@"%d", var); } 但当我将运行目标更改为32位设备(例如iPhone 5)时,会显示如下错误: Cannot initi

ViewController.mm中的以下代码将在64位环境中编译成功,而不会出现任何警告或错误

- (void)viewDidLoad {
    [super viewDidLoad];
    BOOL var = [[NSUserDefaults standardUserDefaults] objectForKey:@"foo"];
    NSLog(@"%d", var);
}
但当我将运行目标更改为32位设备(例如iPhone 5)时,会显示如下错误:

 Cannot initialize a variable of type 'BOOL' (aka 'signed char') with an rvalue of type 'id _Nullable'

我知道这个赋值是不正确的,但是为什么在第一种情况下允许这样做呢?

错误表明您正在将一个对象赋值给BOOL类型的变量。要解决这个问题,您需要使用boolValue将从返回的对象转换为BOOL变量


错误表示您正在将对象分配给BOOL类型的变量。要解决这个问题,您需要使用boolValue将从返回的对象转换为BOOL变量

您的代码: BOOL var=[[NSUserDefaults standardUserDefaults]objectForKey:@foo]; 将一个对象的地址分配给某个大小的int

这几乎总是不是你想要的。您可能想要: BOOL var=[[NSUserDefaults standardUserDefaults]objectForKey:@foo]boolValue]

如果确实要基于该对象的存在进行分配,可以执行以下操作: 布尔变量=!![[NSUserDefaults standardUserDefaults]objectForKey:@foo]

原因是,如果地址的底部8位恰好都是0,那么它可能是一个有效的对象,但将是一个假值,这将是截断赋值的结果

int main(int argc, const char * argv[]) {

    BOOL b = 2;
    if (b == YES)
    {
        NSLog(@"I guess you are right");
    }else{
        NSLog(@"nope");
    }
打印:不

您的代码: BOOL var=[[NSUserDefaults standardUserDefaults]objectForKey:@foo]; 将一个对象的地址分配给某个大小的int

这几乎总是不是你想要的。您可能想要: BOOL var=[[NSUserDefaults standardUserDefaults]objectForKey:@foo]boolValue]

如果确实要基于该对象的存在进行分配,可以执行以下操作: 布尔变量=!![[NSUserDefaults standardUserDefaults]objectForKey:@foo]

原因是,如果地址的底部8位恰好都是0,那么它可能是一个有效的对象,但将是一个假值,这将是截断赋值的结果

int main(int argc, const char * argv[]) {

    BOOL b = 2;
    if (b == YES)
    {
        NSLog(@"I guess you are right");
    }else{
        NSLog(@"nope");
    }
打印:不

对于64位iOS,BOOL类型使用C99\u BOOL类型,有时也可用作BOOL。该类型被定义为只有两个值,0或1。将任何其他值赋给该类型的变量会使其采用值1。也就是说,所有非零值都变为1

因此,赋值不会截断按位值,可能会将非零值转换为零。因此,它在某些方面是安全的,没有理由发出警告。对于一个天真的开发人员来说,这可能仍然是一件令人惊讶的事情,他不理解对象指针和它的值之间的区别,正如其他答案所述,但这是另一回事。

对于64位iOS,BOOL类型使用C99\u BOOL类型,有时也可以作为BOOL使用。该类型被定义为只有两个值,0或1。将任何其他值赋给该类型的变量会使其采用值1。也就是说,所有非零值都变为1


因此,赋值不会截断按位值,可能会将非零值转换为零。因此,它在某些方面是安全的,没有理由发出警告。对于一个天真的开发人员来说,这可能仍然是一件令人惊讶的事情,他不理解对象指针和它的值之间的区别,正如其他答案所述,但这是另一回事。

有几件事解释了为什么会这样做,其中很多都是历史的东西,只是因为过去是这样

布尔是一种相对较新的类型。如果您查看较旧的C代码,您经常会看到它们只使用int,或者像Objective-C编译器一样声明自己的Bool、Bool或Boolean类型

在最初定义Objective-C时,他们使用最小的可能类型签名字符作为BOOL类型

C if语句始终允许使用指针作为其条件,以测试在ObjC的情况下指针是否为NULL或nil

当bool被添加到C标准中时,它基本上被定义为if-takes和so必须具有所有相同行为的类型,包括允许您在预期bool的位置提供一个指针,如果为nil,则将其求值为false,否则为true

苹果无法在旧机器上将BOOL更改为BOOL,因为它会更改@encode返回BOOL的符号,并使旧程序无法与新库链接到同一进程,反之亦然

当64位iOS出现时,许多数据类型已经改变了大小,因此苹果可以安全地将BOOL更改为BOOL,因为没有旧程序需要能够在与新库相同的内存空间中运行。一切都是新的

因此,在将BOOL定义为BOOL的平台上,您会遇到C的向后兼容性特性,它允许您检查空指针。在较旧的平台上,BOOL被定义为
带符号的字符显然不适合指针,并且没有指针的特殊调味汁,因此会产生警告。

有几个因素可以解释这一点,其中很多是历史因素,只是因为过去是这样

布尔是一种相对较新的类型。如果您查看较旧的C代码,您经常会看到它们只使用int,或者像Objective-C编译器一样声明自己的Bool、Bool或Boolean类型

在最初定义Objective-C时,他们使用最小的可能类型签名字符作为BOOL类型

C if语句始终允许使用指针作为其条件,以测试在ObjC的情况下指针是否为NULL或nil

当bool被添加到C标准中时,它基本上被定义为if-takes和so必须具有所有相同行为的类型,包括允许您在预期bool的位置提供一个指针,如果为nil,则将其求值为false,否则为true

苹果无法在旧机器上将BOOL更改为BOOL,因为它会更改@encode返回BOOL的符号,并使旧程序无法与新库链接到同一进程,反之亦然

当64位iOS出现时,许多数据类型已经改变了大小,因此苹果可以安全地将BOOL更改为BOOL,因为没有旧程序需要能够在与新库相同的内存空间中运行。一切都是新的


因此,在将BOOL定义为BOOL的平台上,您会遇到C的向后兼容性特性,它允许您检查空指针。在较旧的平台上,BOOL被定义为一个带符号的字符,显然不适合指针,并且没有针对指针的特殊酱汁,因此会产生警告。

这里不是这样,我将对我的答案进行测试。实际上最简单的示例是NSLog@%d,BOOL256@GradyPlayer,macOS和iOS是不同的。请参阅/usr/include/objc/objc.h,其中它确定objc_BOOL_的默认设置为_BOOL.ok,可能是。。。我会说,如果在语言层面上不能保证,那还是很糟糕的。。。我的意思是,如果我提出相反的论点,我会被否决而死…@GradyPlayer问题是,为什么编译器在一种情况下抱怨32位,而不是其他64位,而不是如何正确编码。没人说代码是好的。即使是OP也表示原始代码有缺陷,他们理解原因。但事实并非如此,我将对我的答案进行测试。实际上最简单的示例是NSLog@%d,BOOL256@GradyPlayer,macOS和iOS是不同的。请参阅/usr/include/objc/objc.h,其中它确定objc_BOOL_的默认设置为_BOOL.ok,可能是。。。我会说,如果在语言层面上不能保证,那还是很糟糕的。。。我的意思是,如果我提出相反的论点,我会被否决而死…@GradyPlayer问题是,为什么编译器在一种情况下抱怨32位,而不是其他64位,而不是如何正确编码。没人说代码是好的。甚至OP也表示原始代码有缺陷,他们理解原因。