2011-04-16 50 views
1

可能重複:
Best way to detect integer overflow in C/C++檢測整數截斷

是什麼,如果發生整數截斷檢測的最佳方式?
編輯
這應當引起截斷而被髮送信號,但它不會

#include <iostream> 

using std::cout; 
typedef signed int int32_t; 
typedef unsigned int uint32_t; 
typedef signed short int16_t; 
typedef unsigned short uint16_t; 


int32_t my32bitInt = 0xffffffff; 

int32_t tmp = my32bitInt & 0xFFFF8000; 

uint16_t ss = my32bitInt; 

int main() 
{ 

    if (tmp != 0xFFFF8000 && tmp != 0x00000000) 
    { // cannot be converted safely 
     cout << "truncation"; 
    } 
     cout << ss << '\n'; 
    cout << my32bitInt << '\n'; 
    return 0; 
} 

編輯2

template <typename U, typename T> 
bool is_safe(T t) 
{ 
    return sizeof(U) <= sizeof(T) ? 
    (t >= static_cast<T>(std::numeric_limits<U>::min())) 
     && (t <= static_cast<T>(std::numeric_limits<U>::max())) : true; 
}  

編輯3(基於奧利奇的<>) - 我發現了一些問題,但在它的工作,將盡快更新

模板 布爾is_safe(來源值) {

if (sizeof(Result) == sizeof(Source)) 
{/*Same size*/ 

    if (std::is_same<Source,Result>::value) 
    { 
     //signed to signed or unsigned to unsigned when size is same - no problem 
     return true; 
    } 
    else 
    { 
     //MSB mustn't be set in Source 
     return !(value & (1u << ((sizeof(Source) * CHAR_BIT) - 1))); 
    } 
} 
else 
{//smaller to larger and larger to smaller 

    if (sizeof(Result) <= sizeof(Source)) 
    { //Larger to smaller and both equal 
     return ((value >= static_cast<Source>(std::numeric_limits<Result>::min())) 
       && (value <= static_cast<Source>(std::numeric_limits<Result>::max()))); 
    } 
    else 
    { //smaller to larger 

     if (std::is_signed<Source>::value && !std::is_signed<Result>::value) 
     { 
      //signed to unsigned - signed must be positive 
      return (value >= 0); 
     } 
     else 
     { 
      return true; 
     } 
    } 
} 

}

+0

你是什麼意思的「截斷」?溢出? – Mat 2011-04-16 09:18:58

+0

本週早些時候我以爲我看到了這個問題,但我現在找不到它。 – 2011-04-16 09:27:53

+0

也許'整數截斷'是整數溢出例如另外。或者,當轉換爲更窄的類型時可能會丟失數據? – 2011-04-16 09:32:10

回答

1

您可以檢查賦值後的值是否相同。

smallInt = largeInt; 

if (smallInt != largeInt) 
{ 
    // Truncation 
} 

或者,你可以前帶口罩檢查:

if (my32bitInt & 0xFFFF0000) 
{ 
    // Can't be assigned to a 16 bit value. 
} 
+1

@Lindydancer是的,這是我所希望的解決方案(第二個)。有趣的是,有多少人(投票結束或發佈虛擬評論的人)沒有看到溢出和截斷之間的差異。再次感謝。 – 2011-04-16 09:41:03

+2

第二種方法不適用於負數(假設二進制補碼)。 – 2011-04-16 09:53:19

+0

@Lindydancer糾正我,如果我錯了,但你的解決方案(第二個)只適用於正數不是嗎? – 2011-04-16 09:55:19

0

我不是一個C++程序員,但我認爲你應該做這樣的事情:

#include <iostream.h> 

int main() 
{ 

    float number = 0.001; 
    if ((int) number == number) 
    { 

     cout << "Hello world"; 
    } 
    return 0; 
} 

。希望是正確的解決方案。

+1

我看不出有什麼好的理由(代碼長度,代碼版權等)讓代碼不在答案中,所以我已將其複製到答案中。 – Rob 2011-04-16 14:36:47

+0

謝謝你!這只是我已經寫過,因爲我的機器上沒有編譯器:D。 – 2011-04-18 10:30:32

0

如果你想檢查沒有做轉換,在一個類型安全的方式,如何執行以下操作:

template <typename U, typename T> 
bool is_safe(T t) 
{ 
    return (t >= (T)std::numeric_limits<U>::min()) 
     && (t <= (T)std::numeric_limits<U>::max()); 
} 

int main() 
{ 
    int32_t a = -32768; 
    int32_t b = +32768; 
    int32_t c = +32767; 
    int32_t d = -32769; 
    std::cout << is_safe<int16_t>(a) << std::endl; // 1 
    std::cout << is_safe<int16_t>(b) << std::endl; // 0 
    std::cout << is_safe<int16_t>(c) << std::endl; // 1 
    std::cout << is_safe<int16_t>(d) << std::endl; // 0 
} 

很明顯,如果UT大一些,但是我相信它可以被修改。

+0

這個怎麼樣...檢查我的編輯。 – 2011-04-16 11:59:11

+0

@There:這確實吸引了大部分案件。但是,我能想到的一種情況是,例如, 'T'是'int16_t','U'是'uint16_t'。但我打賭多一點工作,像這樣的事情可以解決。當然,最簡單的做法就是使用@ LindyDancer的原始測試。 – 2011-04-16 12:03:28

+0

我只是想知道做lindy的方法和花哨的模板檢查之間的性能代價是多少。因爲如果林迪的效率更高,那麼完成複雜的「模板化」工作實際上就沒什麼意義了。 – 2011-04-16 13:34:28

0

最安全的方法是在進行轉換之前檢查它。 These templates完全一樣。例如:

/* unsigned -> signed, overflow */ 
safe_cast<short>(UINT_MAX); 

/* unsigned -> unsigned, overflow */ 
safe_cast<unsigned char>(ULONG_MAX); 

/* signed -> unsigned, overflow */ 
safe_cast<unsigned long>(-1); 

/* signed -> signed, overflow */ 
safe_cast<signed char>(INT_MAX); 

/* always works (no check done) */ 
safe_cast<long>(INT_MAX); 

// giving these assertion failures results 
(type)f <= (type)is_signed<To>::v_max 
f <= (To)-1 
f >= 0 
f >= is_signed<To>::v_min && f <= is_signed<To>::v_max 
+0

我已經「改進」了Oli的<>(請參閱編輯3),所以我認爲它涵蓋了每種情況,並且比您的解決方案「稍微」不那麼複雜(雖然很好)。我想知道你對我的方法有什麼看法? – 2011-04-16 14:24:00