2011-04-16 48 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