3

我正在尝试比较两个整数。一个是 的rowNSIndexPath另一个是countNSArrayrow等于 0 和count等于 2。我将它们放在如下if语句中:

if([self.selectedSetpoint row] < ([self.theCategories count]-3))
{
    //Do true stuff
}

所以根据我的数学,if当我比较时,这个陈述应该是错误的0 < -1。但是,我一直认为这句话是真的,并且里面的块if正在运行。我已尝试使用NSLog这些值来确保我不只是得到错误的值。我把这个放在if声明之前:

NSLog(@"%d",[self.selectedSetpoint row]);
NSLog(@"%d",[self.theCategories count]-3);
NSLog(@"%@",[self.selectedSetpoint row] < ([self.theCategories count]-3)?@"Yes":@"No");

并在控制台上得到了这个:

2012-07-17 08:58:46.061 App[61345:11603] 0
2012-07-17 08:58:46.061 App[61345:11603] -1
2012-07-17 08:58:46.062 App[61345:11603] Yes

任何想法为什么这种比较是真实的?我对比较整数有误解吗?

我有另一个 if 语句就在这个比较的上面

[self.selectedSetpoint row]<([self.theCategories count]-2)

这是0 < 0,它工作正常(返回NO)。所以我觉得使用负整数存在一些问题,我没有得到。

先感谢您。

4

4 回答 4

6

我怀疑这个问题是返回count是一个无符号整数,减去超过它的大小,它会下溢并变得非常大。我已经运行了一些测试,并且得到了与您相同的基本行为(它看起来-1,并且在某些情况下它似乎按预期工作......但是它显然在if()块的上下文中下溢。

愚蠢的问题,但幸运的是有一个简单的解决方案:在 if 语句中将其强制转换:

if([self.selectedSetpoint row] < ( (int)[self.theCategories count] -3 ))
{
    //Do true stuff
}
于 2012-07-17T14:27:11.443 回答
2

我打算提出一个替代解决方案 - 即避免使用减法,而是在等式的另一边使用加法:

if ([self.selectedSetpoint row] + 3 < [self.theCategories count])
{
    //Do true stuff
}

这回避了被这些下溢错误捕获,但是它留下了另一个未触及的问题......即在这个问题的答案中提到的转换规则:在 C 中比较不同数据类型的一般规则是什么?

引用该问题的答案,您会看到 C99 规范指出:

  • (当一个操作数有符号而另一个无符号时)否则,如果无符号整数类型的操作数的秩大于或等于另一个操作数类型的秩,则将有符号整数类型的操作数转换为无符号整数类型的操作数。

所以如果你有一个负值,[self.selectedSetpoint row] + 3那么比较将失败......

这里的其他答案主张将 (NSUInteger) 转换为 (NSInteger) - 但请注意,如果您的无符号值非常大,这可能会导致溢出问题。例如:

(NSInteger) -3 < (NSInteger) 4294967289 == false...

想到必须有一个简单的方法来解决这个问题,我首先想出了一个很难解决的方法......

#define SafeLT(X, Y) \
({ typeof (X) _X = (X); \
   typeof (Y) _Y = (Y); \
( _X < (NSInteger) 0 ? (( _Y > 0) ? YES : _X < _Y ) : ( _Y < (NSInteger) 0 ? NO : _X < _Y));})

无论您如何混合 NSUInteger 和 NSInteger,这都应该有效,并且将确保操作数最多被评估一次(为了提高效率)。

通过正确性证明:

  1. 为了_X < (NSInteger) 0评估为 True,_X 必须是 NSInteger 并且 < 0,所以我们检查 _Y > 0。编译器将通过评估 _Y 的类型来进行正确的比较。如果 Y > 0,那么根据定义,我们返回 YES。否则我们知道 X 和 Y 都是有符号的并且 < 0 并且可以安全地比较它们。
  2. 但是,如果 X 是 NSUInteger 或 > 0,那么我们测试 Y 以查看它是否 < 0。如果 Y 是 < 0,那么根据定义,我们返回 NO。所以现在我们有 X 是 NSUInteger 或 NSInteger > 0 并且 Y 是 NSUInteger 或 NSInteger > 0。由于混合比较将被提升到 NSUInteger 我们每次都会有一个安全的转换,因为没有下溢的机会。

然而,一个更简单的解决方案是将类型转换为更长的有符号整数(如果您的系统有一个):

#define EasySafeLT(X, Y) \
({ long long _X = (X); \
   long long _Y = (Y); \
   ( _X < _Y);})

虽然这取决于是否有更大的类型可用,但可能并不总是可行的。

于 2012-07-17T17:33:19.377 回答
0

问题是count属性有点,NSUInteger当你从一个较小的数字中减去一个更高的数字时,你不会得到一个小于零的数字,你会得到一个非常大的正数,这会导致奇怪的行为。

试试这个方法,你会得到好的结果:

NSLog(@"%@",(NSInteger)[self.selectedSetpoint row] < ((NSInteger)[self.theCategories count]-3)?@"Yes":@"No");
于 2012-07-17T14:33:12.800 回答
0

这似乎是比较有符号整数和无符号整数的情况。您的日志语句将抛出您的假设,因为您要求打印签名的数字。

NSLog(@"%d", -1); //Signed

-1;

NSLog(@"%u", -1); //Unsigned (tested on ios, 32 bit ints)

4294967295;

然后当你比较时:0 < 4294967295肯定是真的。

按照@ctrahey 的建议进行投射应该可以解决您的问题:

if([self.selectedSetpoint row] < ( (int)[self.theCategories count] -3 ))
{
    //Do true stuff
}
于 2012-07-17T14:31:03.957 回答