将无符号整数赋值给有符号整数的相反数,可以吗?

4
当我运行以下代码时:
int main() {
    unsigned a = 5;
    std::cout << -a << std::endl;
    int b = -a; 
    std::cout << b << std::endl;
    return 0;
}

I get this:

4294967291
-5

看起来它可行,我可以把一个unsigned取反并赋值给一个int,但这真的总是OK吗?为什么?

当我尝试类似的情况时:

int c = 1;
int d = 3;
double x = c/d;
std::cout << x << std::endl;

我得到了0(和预期的一样)。

PS:也许有重复,但我没找到。最接近的可能是这个


我“几乎”确定C++从C继承了这种类型转换 - 考虑添加C标签并搜索C领域。例如,阅读此https://dev59.com/QHVD5IYBdhLWcg3wNY1Z。 - PiotrNycz
这只是二进制魔法。相同的二进制表示被解释为有符号或无符号值,其含义不同。 - ilotXXI
无符号整数的减法是否定义行为 - Hayt
@JonnyHenly,“always OK”是指我不确定是否只是碰巧找到了一个例子,因为实际上我并没有预料到这会起作用。第二个例子是因为我唯一能解释这种行为的方式是将rhs在赋值之前以某种方式提升为有符号类型(即lhs上的类型)。 - 463035818_is_not_a_number
2个回答

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表示的最大值。请注意,有符号溢出是未定义行为。因此,该算法对其所有可能的值都不安全。
标准文件(2016-07-12:N4604)中的话:
如果在表达式的求值过程中,结果在其类型的可表示值范围之外或者数学上没有定义,则其行为是未定义的。[注意:除以零、使用零除数形成余数以及所有浮点异常在不同机器上的处理方式各不相同,并且有时可以通过库函数进行调整。——注释]
将来,您可以使用{}样式的初始化来防止这种问题:
unsigned a = 5;
std::cout << -a << '\n';
int b{ -a }; // compiler detects narrowing conversions, warning/error
std::cout << b << '\n';
return 0;

请注意,即使你知道-a将是一个可以用int表示的值,你的编译器仍然会发出警告。
关于有符号整数溢出: C++中有符号整数溢出仍然是未定义行为吗? 关于在C和C ++中定义良好的无符号溢出: 为什么无符号整数溢出是定义良好的行为,但有符号整数溢出不是? 关于隐式转换: http://en.cppreference.com/w/cpp/language/implicit_conversion

2
如果您分配一个大于int所能表示的值,那么就会触发未定义行为(UB)。即使在unsigned上的原始操作是良好定义的。 - user2296177
2
@cmaster 我没有看到过这个。C++14仍然有[expr]/4 如果在表达式的求值过程中,结果在数学上没有定义或者超出了其类型可表示的范围,则行为是未定义的。 - NathanOliver
@cmaster,我添加了最近C++标准中与您说的相矛盾的一句话。请记住,这个问题是关于C++的,您在C语言中可能是正确的。 - user2296177
好的,也许你对C ++是正确的。我会删除我的东西。 - cmaster - reinstate monica

0

只要你的目标架构使用二进制补码算术并将int视为32位,那么就没问题。否则,你的第一个程序会得到不同的结果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接