负整数比较

时间:2012-07-17 14:14:25

标签: iphone objective-c ios

我想比较两个整数。一个是row的{​​{1}},另一个是NSIndexPath的{​​{1}}。 count等于0,NSArray等于2.我将它们放在row语句中,如下所示:

count

所以根据我的数学,if语句应该是假的,因为我正在比较if([self.selectedSetpoint row] < ([self.theCategories count]-3)) { //Do true stuff } 。但是,我一直认为这句话是正确的,if内的块正在运行。我试图0 < -1值,以确保我不只是得到错误的值。我在if声明之前把它放在了正确位置:

NSLog

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

if

为什么这种比较真的如此?我是否误解了比较整数的事情?

我在这个比较

之上的另一个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 ,它运行正常(返回[self.selectedSetpoint row]<([self.theCategories count]-2) )。所以我觉得使用负整数存在一些问题,我没有得到。

提前谢谢。

4 个答案:

答案 0 :(得分:6)

我怀疑问题是count的返回是无符号整数,并且减去超过它的幅度,它会下溢并变得非常大。我已经运行了一些测试,并且我得到了与您相同的基本行为(看起来就像它的-1一样,并且在某些上下文中它出现作为预期......但是在if()区块的背景下,它显然正在下降。

愚蠢的问题,但幸运的是有一个简单的解决方案:在if语句中将其放置到位:

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

答案 1 :(得分:2)

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

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

这可以避免陷入这种类型的下溢错误,但是它留下了另一个未被触及的错误......即在这个问题的答案中提到的转换规则:What are the general rules for comparing different data types in 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且&lt; 0,所以我们检查是否_Y&gt; 0.编译器将通过评估_Y的类型在此进行正确的比较。如果Y> 0然后根据定义我们返回YES。否则我们知道X和Y都是签名的并且&lt; 0,可以安全地比较它们。
  2. 但是,如果X是NSUInteger或&gt; 0然后我们测试Y以查看它是否&lt;如果Y是&lt; 0然后根据定义我们返回NO。所以现在我们有X是NSUInteger或NSInteger&gt; 0和Y是NSUInteger或NSInteger&gt; 0.由于混合比较将被提升为NSUInteger,我们每次都会有一个安全的转换,因为没有下溢的可能性。
  3. 然而,更简单的解决方案是将类型转换为更长的有符号整数(如果您的系统有一个整数):

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

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

答案 2 :(得分:0)

这似乎是将签名的int与未签名的int进行比较的情况。您的日志语句将抛出您的假设,因为您要求打印签名的数字。

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
}

答案 3 :(得分:0)

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

尝试这种方式,你会得到好结果:

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