为什么某些隐式类型转换在机器上是安全的而不是在另一台上?如何防止此跨平台问题?

luc*_*one 5 c++ casting explicit implicit

我最近在我的代码上发现了一个错误,我花了几个小时来调试.

问题出在一个定义为:

unsigned int foo(unsigned int i){
   long int v[]={i-1,i,i+1} ;
       .
       .
       .
 return x ; // evaluated by the function but not essential how for this problem.
}
Run Code Online (Sandbox Code Playgroud)

v的定义在我的开发机器上没有引起任何问题(ubuntu 12.04 32位,g ++编译器),其中unsigned int被隐式转换为long int,因此负值被正确处理.

在另一台机器(ubuntu 12.04 64位,g ++编译器)上,但此操作并不安全.当i = 0时,v [0]没有设置为-1,而是设置为一些奇怪的大值(因为它经常在尝试使无符号int为负时发生).

我可以解决将i的值转换为long int的问题

long int v[]={(long int) i - 1, (long int) i, (long int) i + 1};
Run Code Online (Sandbox Code Playgroud)

一切正常(在两台机器上).

我无法弄清楚为什么第一个在机器上正常工作而在另一个上不起作用.

你能帮助我理解这一点,以便将来可以避免这个或其他问题吗?

Mar*_*k B 6

对于unsigned值,加法/减法被明确定义为模运算,因此0U-1可以得到类似的结果std::numeric_limits<unsigned>::max().

当从unsigned转换为signed时,如果目标类型足够大以容纳无符号值的所有值,那么它只是直接将数据复制到目标类型中.如果目标类型不足以容纳所有无符号值,我相信它的实现已定义(将尝试查找标准引用).

因此,当long64位(可能是您的64位机器上的情况)时,无符号适合并直接复制.

long32位机器上的32位时,它很可能只是将位模式解释为有符号值,在这种情况下为-1.

编辑:避免这些问题的最简单方法是避免混合有符号和无符号类型.从一个概念不允许负数的值中减去一个是什么意思?我将争论函数参数应该是示例中的有符号值.

那就是说g ++(至少是4.5版)提供了一个方便的功能-Wsign-conversion,可以在你的特定代码中检测到这个问题.