2012-07-17 179 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