为什么我可以将值大于127的int传递到char数组中,但不能直接传递



我知道char值不能表示为176,但有些字节系统是无符号的(0-255(,而另一些字节系统是有符号的(-128到127(。在这种情况下,我使用的是unsigned,所以我只想创建一个简单的字节消息数组,但当我试图放置一个高于127的值时,我会遇到这个错误,但如果我首先将其声明为int,它会避免这个错误。有人能详细解释一下为什么这样做吗?

方法1:不起作用。我得到这个错误:缩小了从"int"到"char"的"176"的转换

char m1[3]{ 176, 118, 1 };

方法2:有效

int b1 = 176;
char m1[3]{ b1, 118, 1 };

使用大括号进行初始化(也称为"统一初始化"(时,不允许缩小转换范围。否则,它们就是,并且值只是被静默地截断。

大多数编译器都有可以启用的警告选项,这些选项将捕获发生截断的许多(但不是所有(实例。他们通常也有可以将此类警告转化为错误的选项。您应该使用这些选项。

如果您想使用字节,那么std::byte可以说是正确的使用类型。或者(如果不能使用(std::uint8_t。

这两种情况都是格式错误的,但正如我在这里的回答中所解释的,格式错误只需要诊断。该诊断是警告还是错误取决于实现。所以这是一个非常符合要求的结果。

例如,对于这种情况,gcc为第一个生成错误,但仅为第二个生成警告(请参阅godbolt上的实时消息(:

error: narrowing conversion of '176' from 'int' to 'char'  [-Wnarrowing]
2 |     char m1[3]{ 176, 118, 1 };
|                             ^
warning: narrowing conversion of 'b1' from 'int' to 'char' [-Wnarrowing]
5 |    char m2[3]{ b1, 118, 1 };
|                           ^ 

这是标准允许的,我将引用这个gcc错误报告中的相关部分:

该标准只要求";一致性实现应发出至少一个诊断消息";因此允许编译带有警告的程序。正如Andrew所说,-Werror=如果你愿意,缩小可以使它成为一个错误。

G++4.6给出了一个错误,但它被故意更改为4.7的警告,因为许多人(包括我自己(发现,在试图将大型C++03代码库编译为C++11时,缩小转换是最常见的问题之一。以前格式良好的代码,如char c[]={i,0};(其中我只会在char的范围内(导致错误,必须更改为char c[]={(char(i,0}

使用gcc和clang,可以使用-Werror将所有警告转化为错误。

大多数系统上的典型字符范围:

  • 类型:char,范围:-127到1270到255
  • 类型:无符号字符,范围:0到255
  • 类型:有符号字符,范围:-127到127

char有符号还是无符号符号的,编译器检测到您正在从正整数(10110000=176(隐式转换为有符号字符值(其中10110000为-90(。如果值小于或等于127,则不会生成警告(请尝试!(。如果你想避免隐式转换(缩小转换(,你可以显式指定它是无符号:

unsigned char m1[3]{ 176, 118, 1 };

如果要使用有符号字符,最好使用signed修饰符,而不是依赖于实现:

signed char m1[3]{ b, 118, 1 }; // where b is less than or equal to 127

对于{}-初始化,编译器至少应该将其诊断为警告,这会导致程序格式错误。但同样,这取决于所使用的编译器和选项。如果你去https://gcc.godbolt.org/并使用不同的编译器/选项编译代码,您可以看到差异。

一些例子:

对于以下代码:

char m1[3] = {176, 118, 1 };
  • 使用x86-64 gcc 6.1时,会得到一个错误:error: narrowing conversion of '176' from 'int' to 'char' inside { } [-Wnarrowing]。然而,当您使用标志-Wno-narrowing时,您不会得到它,但您的程序仍然是格式错误的,您不希望这样
  • 使用x86-64 gcc 4.8.1,您不会得到任何错误和警告。但是,例如,当使用选项-Wno-narrowing-Werror=narrowing时,您可以看到它被拒绝,并分别显示警告或错误

使用代码:

int b1 = 176;
char m1[3] = {b1, 118, 1 };

使用不同的编译器版本会得到不同的行为,但程序仍然是格式错误的。

一般来说,无论编译器的哪个版本(我想,我没有检查所有版本(,使用-Wnarrowing-Wall-Werror=narrowing等选项都应该指出缩小的转换,这意味着你的程序格式不正确,你不希望这样。

我希望这能有所帮助!

相关内容

  • 没有找到相关文章

最新更新