将无符号的负数分配给有符号的,可以吗?

Assign negative of unsigned to a signed, is it OK?

当我运行这个:

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(如预期)。

PS:也许有一个骗子,但我没有找到,我能找到的最接近的是

只要您的目标体系结构使用二进制补码算法并将 int 视为 32 位,就可以了。否则你的第一个程序会得到不同的结果。

。您有 未定义的行为 种可能性。

这是一个反例,在将取反的 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 可以表示的最大值。知道有符号溢出是未定义的行为。因此,该算法对其所有可能值都不安全。

标准的(2016-07-12:N4604)词:

If during the evaluation of an expression, the result is not mathematically defined or not in the range of representable values for its type, the behavior is undefined. [ Note: Treatment of division by zero, forming a remainder using a zero divisor, and all floating point exceptions vary among machines, and is sometimes adjustable by a library function. — end note ]


将来,您可以使用 {} 式初始化来防止此类问题:

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