2012-07-17 129 views
2

我想比较两个整数。一个是NSIndexPathrow,另一个是NSArraycount。该row等于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)[email protected]"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)。所以我觉得使用负整数有一些问题,我没有得到。

预先感谢您。

+0

如果你的意思是-1应该是+1,你可以使用ABS(theCategories.count),所以它返回整数的绝对值。 – 2012-07-17 14:21:16

+9

是不是因为你在比较NSUInteger和NSInteger? – Luke 2012-07-17 14:22:31

+0

@EPyLEpSY不,我没有试图获得绝对值,我希望它比较0和-1。 – 2012-07-17 14:24:05

回答

5

我怀疑的问题是,count返回的是一个无符号整数,并减去比它的幅度更大,下溢,变得相当大。我已经进行了一些测试,并且我得到了和你一样的基本行为(它看起来像就像它的-1一样,并且在某些情况下出现按预期工作......但是它明显地在。在if()

愚蠢的问题,但幸运的是有一个简单的解决方案:演员到位的if语句:

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

什么一个菜鸟的错误!谢谢! – 2012-07-17 14:33:33

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 
} 
+0

感谢关于日志扔掉我的信息。尽管为了得到支票,你已经很迟钝了! – 2012-07-17 14:44:54

+0

我知道!我正在写答案,因为我看到了另一个。我只是继续因为有关NSLog的额外信息。 =] – 2012-07-17 14:56:08

0

问题是count属性是一种NSUInteger,当你减去一个较小的一个较大的数字,你不会得到一个小于零号码,你会得到一个非常大的正数,它会导致奇怪的行为。

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

NSLog(@"%@",(NSInteger)[self.selectedSetpoint row] < ((NSInteger)[self.theCategories count]-3)[email protected]"Yes":@"No"); 
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的和< 0,所以我们检查,如果_Y> 0,编译器会做出正确的比较,在这里通过评估_Y的类型。如果Y> 0,那么根据定义,我们返回YES。否则,我们知道X和Y都有符号并且可以安全地进行比较。
  2. 然而,如果X是NSUInteger或> 0,那么我们测试y以看它是否是< 0。如果Y是< 0然后通过定义,我们返回NO。所以现在我们有X是NSUInteger或NSInteger> 0和Y是NSUInteger或NSInteger> 0.由于混合比较将被提升为NSUInteger,我们将每次都有一个安全的转换,因为没有下溢的机会。

一个简单的办法,但是,这是只是强制转换为较长的有符号整数(IFF系统有一个):

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

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

+0

感谢您的所有信息! – 2012-07-17 18:20:46