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

时间:2018-11-20 02:11:59

标签: 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 initialize a variable of type 'BOOL' (aka 'signed char') with an rvalue of type 'id _Nullable'

我确实知道这项工作很麻烦,但是为什么在第一种情况下允许这样做?

4 个答案:

答案 0 :(得分:3)

对于64位iOS,BOOL类型使用C99 _Bool类型(有时也可以作为bool使用)。将该类型定义为仅具有两个值,即0或1。将其他任何值分配给该类型的变量,将使其采用值1。(即,所有非零值都变为1。)

因此,赋值不会截断按位值,可能会将非零值转换为零。因此,从某种意义上讲它是“安全的”,没有警告的理由。 (对于一个天真的开发人员,仍然不感到惊讶,因为他不了解对象的指针与其值之间的区别,正如其他答案所解决的那样,但这是另一回事。)

答案 1 :(得分:1)

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

BOOL var = [[[NSUserDefaults standardUserDefaults] objectForKey:@"foo"] boolValue];

答案 2 :(得分:1)

您的代码:
AttributeError: Tensor.name is meaningless when eager execution is enabled.
正在将对象的地址分配给某种大小的int ...

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

如果您确实想根据该对象的存在进行分配,则可以执行以下操作:
BOOL var = [[[NSUserDefaults standardUserDefaults] objectForKey:@"foo"]boolValue];

原因是,如果地址的后8位全部为0,则它​​可能是有效对象,但将是错误值,这是截断分配的结果。

BOOL var = !![[NSUserDefaults standardUserDefaults] objectForKey:@"foo"];

打印:int main(int argc, const char * argv[]) { BOOL b = 2; if (b == YES) { NSLog(@"I guess you are right"); }else{ NSLog(@"nope"); }

答案 3 :(得分:1)

起作用的原因有很多,其中许多历史性的东西只存在,因为它曾经是那样。

  1. bool是一种相对较新的类型。如果您查看旧的C代码,通常会发现它们只是使用int,或者像Objective-C编译器一样声明自己的BoolBOOL或{{1 }}类型。

  2. 返回最初定义Objective-C时,他们为Boolean类型使用了最小的类型(signed char)。

  3. C BOOL语句始终允许使用指针作为其条件,以测试指针不是if(或ObjC情况下的NULL)。

  4. nil添加到C标准时,它基本上被定义为“ bool所采用的类型”,因此必须具有所有相同的行为,包括允许您提供一个指针,该指针应为预期的布尔值,如果为if则为false,否则为nil

  5. Apple无法将旧计算机上的true更改为BOOL,因为它会更改bool会返回@encode()的符号,并且使得旧程序无法与新库链接到同一进程(反之亦然)。

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

因此,在将bool的新定义为BOOL的平台上,您会遇到C的向后兼容功能,即让您检查bool指针。在较旧的平台上,NULL被定义为BOOL,显然不适合指针,并且没有特殊的指针,因此会产生警告。