将无符号的负数赋值给有符号,可以吗?

for*_*818 5 c++ unsigned type-conversion

当我运行这个时:

int main() {
    unsigned a = 5;
    std::cout << -a << std::endl;
    int b = -a; 
    std::cout << b << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我明白了:

4294967291
-5
Run Code Online (Sandbox Code Playgroud)

看起来它有效,我可以取 an 的负数unsigned并将其分配给 an int,但这真的总是可以吗?为什么?

当我尝试一些对我来说看起来类似的情况时:

int c = 1;
int d = 3;
double x = c/d;
std::cout << x << std::endl;
Run Code Online (Sandbox Code Playgroud)

我明白了0(正如预期的那样)。

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

use*_*177 5

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

\n\n

下面是一个反例,当将否定分配unsigned int给 an时,会产生 UB int

\n\n
unsigned u = (unsigned)std::numeric_limits<int>::max() - 1;\nstd::cout << "max int" << std::numeric_limits<int>::max() << \'\\n\';\nstd::cout << "as unsigned - 1" << u << \'\\n\';\nstd::cout << "negated:" << -u << \'\\n\';\nstd::cout << std::boolalpha << ( std::numeric_limits<int>::max() < -u ) << \'\\n\';\nint s = -u;\nstd::cout << s << \'\\n\';\n
Run Code Online (Sandbox Code Playgroud)\n\n

在我的机器上:\n int\ 的最大值是 2\'147\'483\'647,但求反的unsigned int值为 2\'147\'483\'650;该值大于 可以表示的最大值int。知道有符号溢出是未定义的行为。因此,该算法对于所有可能的值来说并不安全。

\n\n

标准(2016-07-12:N4604)字样:

\n\n
\n

如果在计算表达式期间,结果未在数学上定义或不在其类型的可表示值范围内,则行为未定义。[ 注意:除以 0 的处理、使用零除数形成余数以及所有 \xef\xac\x82oating point\n 例外情况因机器而异,有时可以通过库函数进行调整。\xe2\x80\x94 尾注]

\n
\n\n
\n\n

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

\n\n
unsigned a = 5;\nstd::cout << -a << \'\\n\';\nint b{ -a }; // compiler detects narrowing conversions, warning/error\nstd::cout << b << \'\\n\';\nreturn 0;\n
Run Code Online (Sandbox Code Playgroud)\n\n

请注意,即使您知道这-a将是一个可以由 表示的值int,您的编译器仍然会警告您。

\n\n

关于签名溢出:

\n\n

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

\n\n

关于 C 和 C++ 中定义明确的无符号溢出:

\n\n

为什么无符号整数溢出定义了行为,但有符号整数溢出却没有定义?

\n\n

关于隐式转换:

\n\n

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

\n

  • @cmaster 如果您分配的值大于“int”可以表示的值,则会触发 UB。即使对“unsigned”的原始操作已明确定义。 (2认同)
  • @cmaster 我还没有看到。C++14 仍然具有 [expr]/4 *如果在表达式求值期间,结果未在数学上定义或不在其类型的可表示值范围内,则行为未定义。* (2认同)