0%

一个浮点数引发的悲剧

不期而遇

某天我开开心心地写了一段代码:

1
2
3
NSInteger a = 10;
NSUInteger b = 9;
CGFloat c = -4 - (a - b - 1) * 13;

我预期c值为-4,但是编译器却输出了一个:

![截屏2021-06-17 上午11.56.32](/Users/Joshsone/Library/Application Support/typora-user-images/截屏2021-06-17 上午11.56.32.png)

WTF?这是啥,因为这莫名的缘分,我展开了一段追根溯源的路程。

寻觅之旅

为了厘清这段神秘的数字到底从何而来,我将Xcode调整为Always Show Disassembly,来看看编译器到底做了些啥?

![截屏2021-06-17 下午12.05.44](/Users/Joshsone/Library/Application Support/typora-user-images/截屏2021-06-17 下午12.05.44.png)

这段汇编代码对应到执行完-4 - (a - b - 1) * 13,但是还没有赋值给c,寄存器rax中存放的就是计算结果,我们打印来看下:

1
2
(lldb) expression $rax
(unsigned long) $0 = 18446744073709551612

可以看出rax中存放的是无符号长整形,其二进制形式是:

1
2
(lldb) p/t 18446744073709551612
(unsigned long long) $1 = 0b1111111111111111111111111111111111111111111111111111111111111100

可以看到,代码执行到这一步,已经出现了问题,我们期待结果是负数,那必然就是有符号整形,但是由于我们将b声明为NSUInteger,系统便将计算结果强转为了NSUInteger

另外提一句:有符号的-4,二进制格式也为0b1111111111111111111111111111111111111111111111111111111111111100