为什么将 256 分配给 char 会引发警告,但分配 255 不会,但两者都会导致整数溢出?

Why does assigning 256 to a char raise a warning, but assigning 255 don't, but both result in integer overflow?

考虑这个例子:

#include <iostream>
int main()
{
    char c = 256;
    std::cout << static_cast<int>(c);
}

发出警告:

warning: overflow in conversion from 'int' to 'char' changes value from '256' to ''[=11=]0'' [-Woverflow]

但是这个:

#include <iostream>
int main()
{
    char c = 255;
    std::cout << static_cast<int>(c);
}

不,但是 std::cout 在这两种情况下都不会打印 256255,所以它显示 char can't hold [=14] =] 和 255,但仅当 char c256?

时才会发出警告

你可以玩玩它here

在您的示例中指定 char 是否已签名很重要,但是根据您的 link 它已签名。

如果你写

char c = 256;

256 的类型为 int,因此要将值存储在 c 中,必须转换为 char

对于有符号的目标类型,如果它在目标类型中是可表示的,则此类整数转换会产生相同的值。这将具有典型的位大小和有符号字符的表示形式 -128127.

如果源值在目标类型中不可表示,会发生什么情况取决于几个因素。

首先,由于 C++20 二进制补码是有保证的,这意味着结果值保证是唯一值,因此它和源值等于模 2^nn 目标类型的位大小(对于 char 通常是 8)。

在 C++20 之前,它是 实现定义的 在这种情况下会发生什么,但很可能实现只指定了与 C+ 等效的行为+20 一

因此,警告并不是为了防止未定义的行为,甚至是自 C++20 以来的实现定义的行为,而只是为了通知用户可能的错误。

我无法确定为什么 GCC 选择仅对大于 255 的值发出警告,但我的猜测是这样做是因为像

这样的语句
char c = 255;
如果您将右侧解释为 unsigned char

就有意义了。上面解释的转换规则不会改变转换前后表示的字符。

不过

char c = 256;
如果右侧被解释为 unsigned char

甚至没有意义。所以这是一个错误的可能性似乎更高。

但也许我也猜错了方向。关于 -Woverflow 警告的这种行为,GCC 有一个开放的 bug report。通过阅读那里的评论,我不清楚这种行为最初的原因是什么。

例如,Clang 始终警告所有超出范围的值。所以警告中似乎有不同的想法。