为什么我可以将值大于127的int传递给char数组,而不是直接传递给char数组?

时间:2018-11-08 18:25:40

标签: c++ char byte unsigned signed

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

方法1:不起作用。我收到此错误消息:将“ 176”的转换范围从“ int”转换为“ char”

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

方法2:有效

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

3 个答案:

答案 0 :(得分:3)

在使用花括号进行初始化(又称为“统一初始化”)时,则不允许缩小转换。否则,值将被静默截断。

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

如果要使用字节,那么std::byte可以说是正确的类型。或者(如果无法使用)std::uint8_t

答案 1 :(得分:1)

这两种情况都是不正确的,但是正如我在my answer here中所解释的那样,仅需要诊断。该诊断是警告还是错误取决于实施。因此,这非常符合要求。

例如,在这种情况下,gcc对第一个错误产生错误,而对第二个错误仅产生警告(see it live on 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 };
      |                           ^ 

这是标准允许的,我将引用this gcc bug report的relevent部分:

  

该标准仅要求“合格的实施方案应发出至少一条诊断消息”,因此允许使用警告编译程序。正如安德鲁所说,-Werror = narrowing允许您根据需要将其设置为错误。

     

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

同时使用gcc和clang,您可以使用-Werror将所有警告变为错误。

答案 2 :(得分:0)

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

  • 类型:字符,范围: -127至127 0至255
  • 类型:无符号字符,范围: 0至255
  • 类型:签名字符,范围: -127至127

char signed 还是 unsigned 是实现定义的。您可以使用std::is_signed<char>()进行检查。在您的情况下,它是隐式的 signed ,编译器检测到您正在隐式地将正整数(10110000 = 176)转换为带符号的字符值(其中10110000为-90)。如果值小于或等于127,则不会生成警告(尝试!)。 如果要避免隐式转换(缩小转换),可以显式指定其为 unsigned

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之类的选项与编译器的任何版本(我想,我都没有检查所有选项)缩小的转换范围,这意味着您的程序格式错误,并且您不希望这样做。

我希望这会有所帮助!