把负的或无符号的赋值给有符号的,可以吗

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

本文关键字:符号 无符号 赋值      更新时间:2023-10-16

当我运行这个时:

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:也许有一个骗局,我没有找到它,我能找到的最接近的是这个

。你有未定义行为的可能性。

这里是一个反例,当将否定的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) word:

如果在表达式求值期间,结果不是在数学上定义的或不在可表示值范围内的它的类型、行为是未定义的。[注:除法处理按零,使用零除数形成余数,以及所有浮点数异常因机器而异,有时可通过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表示的值,您的编译器仍然警告您。

On signed overflow:

有符号整数溢出在c++中仍然未定义行为吗?

C和c++中定义良好的无符号溢出:

为什么无符号整数溢出是定义行为,而有符号整数溢出是n't?

关于隐式转换:

http://en.cppreference.com/w/cpp/language/implicit_conversion

只要您的目标架构使用2的互补算法并将int视为32位,就可以了。否则,第一个程序将得到不同的结果。