在我的部分代码中,我正在编写一个简单的for
循环来迭代数组中的元素(所有NSMutableDictionary
),我发现即使条件基本为1,循环也会执行<1 .
NSMutableArray* arr = [[NSMutableArray alloc] init];
NSLog(@"COUNT: %d | %i", arr.count, 1 < (arr.count - 1));
输出为:
COUNT: 0 | 1
这实际上意味着计数为0,并且1小于-1。
我想这可能是因为数组刚刚初始化,也许添加和删除对象可能会改变一点所以我继续这样做:
NSMutableArray* arr = [[NSMutableArray alloc] init];
[arr addObject:@1];
[arr removeObject:@1];
NSLog(@"COUNT: %d | %i", arr.count, 1 < (arr.count - 1));
仍然是相同的结果:
COUNT: 0 | 1
我想到的可能的原因:
- 有一些关于编译器/objective-C的东西,我还不明白
- 在我的Mac寄存器闹鬼
- 我快要疯了
我非常怀疑这是最后两种情况中的任何一种,但我还是想知道为什么会发生这种情况
arr.count
为无符号整数值(类型为NSUInteger
)。在无符号算术中,(0 - 1)
会绕到一个非常大的正数,而-1
不会。
如果将值强制转换为有符号整数,可能会看到预期的结果:
NSLog(@"COUNT: %d | %i", (int)arr.count, 1 < ((int)arr.count - 1));
查看这个主题的一些方法来处理这个常见的bug来源:常量bug从[NSArray count]是unsigned
发生这种情况的原因是左边的1
被视为无符号。反过来,这是因为arr.count
是无符号类型,使得表达式arr.count-1
也是无符号的。当你从一个无符号零中减去1
时,你会得到一个下溢,结果是一个非常大的正数。
为了避免这样的问题,在处理unsigned
类型的值时,要非常小心减法。更喜欢添加到另一边——特别是,而不是写
if (a < unsignedB - c)
写if (a+c < unsignedB)
数组的count
属性为NSUInteger
类型,即unsigned long
。表达式arr.count - 1
从无符号整数中减去1,因此结果也是无符号的。因为溢出,你得到的不是-1而是一个非常大的正数,这个数大于1
[arr count]
返回(NSUInteger)
,即typedef unsigned long NSUInteger;
所以NSUInteger
不会有任何负数。值从0开始到某个最大值,它将像下面这样的循环
... | MAX-2 | MAX-1 | MAX | 0 | 1 | 2 | 3 | 4 | ...
-1 -1 -1 -1 -1 -1 -1
So, the math is like 2-1 = 1
1-1 = 0
0-1 = MAX
0-2 = MAX-1