【问题标题】:Narrowing Conversion from int to char inside { } | An issue with signedness of char在 { } | 内缩小从 int 到 char 的转换char 的签名问题
【发布时间】:2020-08-21 13:55:06
【问题描述】:

查看charvector<char> 和独立char 的情况下的行为:

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> someInts = {2, 3, 1 + 5};
    // I can perform operations   ^^^^^   inside the braces in this case

    // vector<char> someChars = {'a', 'b', 'r' + 'z'};
    // But doing the same in case of char  ^^^^^^^^^  gives an error

    // However, it works for a standalone char
    char ch = 'r' + 'z';
    cout << ch;
    // Value^^^is '∞' as expected
}

取消注释 vector&lt;char&gt; 行给出:

错误:在 {}

内将“236”从“int”缩小到“char”

这就是问题所在。


然后我阅读了 List Initializationthis 文档,看到了可能与此问题有关的以下内容:

缩小转化范围

list-initialization 通过以下方式限制允许的隐式转换 禁止:

  • 许多其他原因
  • 从整数或无作用域枚举类型转换为不能表示原始所有值的整数类型,除非在 source 是一个常量表达式,其值可以精确存储 在目标类型中

它让我理解了错误消息(我猜),我将 vector&lt;char&gt; 更改为 vector&lt;unsigned char&gt; 并且它起作用了:

vector<unsigned char> someChars = {'a', 'b', 'r' + 'z'};
for (char ch : someChars)
    cout << '_' << ch;

输出:_a_b_∞


所以,我的问题是:

  1. 如果char签名 是问题所在,那么char 的独立版本在这种情况下如何工作?参考stackoverflow上的this线程,同一个编译器如何为vector&lt;char&gt;选择signed char,为unsigned char选择char

  2. 如果我对问题的推断是错误的,那么这个问题背后的正确原因是什么?

【问题讨论】:

标签: c++ vector char int list-initialization


【解决方案1】:

1+5 是一个int,所以使用它来初始化一个vector&lt;int&gt; 条目没有问题。

'r' + 's' 是一个int (236),它超出了您系统上char 的范围。所以存在一个问题,试图使用它来初始化vector&lt;char&gt; 条目。这正是列表初始化不允许缩小转换的规则所设计的那种情况。

vector&lt;char&gt; x = { 'a', 'b', 123456 }; 会出现同样的错误

独立的char 具有与signed charunsigned char 相同的属性,它是实现定义的,并且一些编译器有一个可供选择的开关(例如,GCC 上的-funsigned-char)。需要明确的是,无论哪种情况,它仍然是一个独特的类型。


用你的话来说,char 确实在这两种情况下都被签名了,正如 Nathan Oliver 在 cmets 中解释的那样。问题是您错误地认为独立的char 在您的情况下是未签名的。仅仅因为 char ch = 'r' + 'z'; 已编译并没有表明它是未签名的。您可能认为它是未签名的,因为 'r' + 'z' == 236 不适合 signed char。不,它确实适合 signed char,原因如下:

char ch = 'r' + 'z';超出范围的转换。从 C++20 开始,结果将是 -20(假设普通字符是 8 位签名的,如您之前的错误消息所示,并且系统使用 ASCII 编码),在此之前,结果是实现定义的。


所以,不要假设事情。如果您对系统上的 char 是已签名还是未签名感到困惑,只需检查 CHAR_MIN

【讨论】:

  • which is out of range of for char on your system替换which is out of range of char?
  • 'r' + 's'236。如您所说,它可能超出char 的范围,但前提是它是signed char。那么vector&lt;char&gt; 也应该是vector&lt;signed char&gt;。但在我的情况下,vector&lt;char&gt; 确实是 vector&lt;signed char&gt;,但 r + s charunsigned char
  • @ArdentCoder charsigned char 是不同的类型,但在您的系统上具有相同的属性
  • 我不是在谈论123456,这显然超出了范围。我正在处理我的代码中的236,它在unsigned char 的范围内。但是正如您所说,它依赖于编译器,我的编译器将其视为signed char,我同意。那为什么我的代码中的另一个char 没有被视为已签名,因为它按预期编译并显示了无穷大符号。
  • @ArdentCoder -- 如果不清楚:char 的签名由编译器确定,编译器在整个编译过程中使用 same 签名。它不会在编译单个源文件时做出个案决定。一些编译器为您提供了一个命令行开关,让您可以选择使用哪一个,但同样适用于整个编译过程。
猜你喜欢
  • 2020-06-20
  • 1970-01-01
  • 2014-12-04
  • 1970-01-01
  • 1970-01-01
  • 2019-04-05
  • 2019-03-15
  • 2014-05-18
  • 2015-10-16
相关资源
最近更新 更多