当我运行时:
int main() {
unsigned a = 5;
std::cout << -a << std::endl;
int b = -a;
std::cout << b << std::endl;
return 0;
}
我明白了:
4294967291
-5
似乎它有效,我可以接受unsigned
的否定并将其分配给int
,但这真的总是好吗?为什么?
当我尝试一些对我来说类似的情况时:
int c = 1;
int d = 3;
double x = c/d;
std::cout << x << std::endl;
我得到0
(正如预期的那样)。
答案 0 :(得分:4)
否即可。您有未定义的行为可能性。
这是一个反例,在向unsigned int
指定否定的int
时会产生UB:
unsigned u = (unsigned)std::numeric_limits<int>::max() - 1;
std::cout << "max int" << std::numeric_limits<int>::max() << '\n';
std::cout << "as unsigned - 1" << u << '\n';
std::cout << "negated:" << -u << '\n';
std::cout << std::boolalpha << ( std::numeric_limits<int>::max() < -u ) << '\n';
int s = -u;
std::cout << s << '\n';
在我的机器上:
int
的最大值是2'147'483'647,但是否定的unsigned int
的值为2'147'483'650;该值大于int
可表示的最大值。知道签名溢出是未定义的行为。因此,该算法对于所有可能的值都不安全。
The Standard's(2016-07-12:N4604)字样:
如果在评估表达式期间,结果不是 在数学上定义或不在可表示值的范围内 它的类型,行为是未定的。 [注:治疗分裂 零,使用零除数形成余数,以及所有浮点 机器之间的例外情况各不相同,有时可以通过a调整 库函数。 - 结束说明]
将来,您可以使用{}
- 样式初始化来防止此类问题:
unsigned a = 5;
std::cout << -a << '\n';
int b{ -a }; // compiler detects narrowing conversions, warning/error
std::cout << b << '\n';
return 0;
请注意,即使您知道-a
将是一个可由int
表示的值,您的编译器仍然会发出警告。
签名溢出:
Is signed integer overflow still undefined behavior in C++?
在C和C ++中明确定义的无符号溢出:
Why is unsigned integer overflow defined behavior but signed integer overflow isn't?
隐式转化:
http://en.cppreference.com/w/cpp/language/implicit_conversion
答案 1 :(得分:0)
只要你的目标架构使用两个补码算法并将int
视为32位就可以了。否则,您的第一个程序会得到不同的结果。