为什么我可以将一个大于 127 的 int 传递给一个 char 数组,而不是直接传递?
Why can I pass an int with a value higher than 127 into a char array, but not directly?
我知道 char 值不能表示为 176,但一些字节系统是无符号的 (0-255),而其他字节系统是有符号的(-128 到 127)。在这种情况下,我使用的是无符号的,所以我只想创建一个简单的字节消息数组,但是当我尝试放置一个高于 127 的值时出现此错误,但是如果我先将其声明为 int,它会避免该错误.有人可以详细解释为什么这有效吗?
方法一:不行。我收到此错误:缩小从“int”到“char”的“176”转换
char m1[3]{ 176, 118, 1 };
方法 2:这个有效
int b1 = 176;
char m1[3]{ b1, 118, 1 };
当使用花括号进行初始化(又名 "uniform initialization")时,不允许缩小转换。否则它们是并且值只是被静默截断。
大多数编译器都有警告选项,您可以启用这些选项,以捕获许多(但不是全部)发生截断的实例。他们通常还有可以将此类警告变成错误的选项。
您应该使用这些选项。
如果你想使用字节,那么 std::byte is arguably the correct type to use. Or (if you cannot use that) std::uint8_t。
大多数系统上的典型字符范围:
- 类型:char,范围:-127 到 127 或 0 到 255
- 类型:unsigned char,范围:0 到 255
- 类型:signed char,范围:-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/ 并使用不同的 compilers/options 编译您的代码,您会看到差异。
一些例子:
对于以下代码:
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
之类的选项以及任何版本的编译器(我想,我没有检查所有这些选项),应该指出收缩转换,这意味着您的程序格式错误,您不希望这样。
希望对您有所帮助!
这两种情况都是错误格式的,但正如我在 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的相关部分:
The standard only requires that "a conforming implementation shall issue at least one diagnostic message" so compiling the program with a warning is allowed. As Andrew said, -Werror=narrowing allows you to make it an error if you want.
G++ 4.6 gave an error but it was changed to a warning intentionally for 4.7 because many people (myself included) found that narrowing conversions where one of the most commonly encountered problems when trying to compile large C++03 codebases as C++11. Previously well-formed code such as char c[] = { i, 0 }; (where i will only ever be within the range of char) caused errors and had to be changed to char c[] = { (char)i, 0 }
对于 gcc 和 clang,您可以使用 -Werror
.
将所有警告转换为错误
我知道 char 值不能表示为 176,但一些字节系统是无符号的 (0-255),而其他字节系统是有符号的(-128 到 127)。在这种情况下,我使用的是无符号的,所以我只想创建一个简单的字节消息数组,但是当我尝试放置一个高于 127 的值时出现此错误,但是如果我先将其声明为 int,它会避免该错误.有人可以详细解释为什么这有效吗?
方法一:不行。我收到此错误:缩小从“int”到“char”的“176”转换
char m1[3]{ 176, 118, 1 };
方法 2:这个有效
int b1 = 176;
char m1[3]{ b1, 118, 1 };
当使用花括号进行初始化(又名 "uniform initialization")时,不允许缩小转换。否则它们是并且值只是被静默截断。
大多数编译器都有警告选项,您可以启用这些选项,以捕获许多(但不是全部)发生截断的实例。他们通常还有可以将此类警告变成错误的选项。 您应该使用这些选项。
如果你想使用字节,那么 std::byte is arguably the correct type to use. Or (if you cannot use that) std::uint8_t。
大多数系统上的典型字符范围:
- 类型:char,范围:-127 到 127 或 0 到 255
- 类型:unsigned char,范围:0 到 255
- 类型:signed char,范围:-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/ 并使用不同的 compilers/options 编译您的代码,您会看到差异。
一些例子:
对于以下代码:
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
之类的选项以及任何版本的编译器(我想,我没有检查所有这些选项),应该指出收缩转换,这意味着您的程序格式错误,您不希望这样。
希望对您有所帮助!
这两种情况都是错误格式的,但正如我在 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的相关部分:
The standard only requires that "a conforming implementation shall issue at least one diagnostic message" so compiling the program with a warning is allowed. As Andrew said, -Werror=narrowing allows you to make it an error if you want.
G++ 4.6 gave an error but it was changed to a warning intentionally for 4.7 because many people (myself included) found that narrowing conversions where one of the most commonly encountered problems when trying to compile large C++03 codebases as C++11. Previously well-formed code such as char c[] = { i, 0 }; (where i will only ever be within the range of char) caused errors and had to be changed to char c[] = { (char)i, 0 }
对于 gcc 和 clang,您可以使用 -Werror
.