【问题标题】:"Narrowing conversion from 'int' to 'char' inside { }" for legal values when cross compiling交叉编译时,“在 {} 内缩小从 'int' 到 'char' 的转换”以获得合法值
【发布时间】:2015-10-16 13:38:34
【问题描述】:

我有一个 C++ 项目,我在我的机器上使用 g++ 编译(编译到“主机”)和使用交叉编译器(在我的情况下为 arm-cortex_a8-linux-gnueabi-g++)编译到 ARM 处理器。我正在转换为 C++0x/11 标准,编译初始化列表时出现错误,我能够在以下 sn-p 中重现该错误:

int main(void) {
    char c[1] = {-108};
}

这个程序看起来是正确的,因为-108char 的合法值。 使用g++ 编译它不会产生以下命令行错误:

g++ example.cc -std=c++0x

但是,当我使用交叉编译器进行编译时,如下所示:

arm-cortex_a8-linux-gnueabi-g++ example.cc -std=c++0x

我收到以下错误:

example.cc: In function 'int main()':
example.cc:2:22: error: narrowing conversion of '-0x0000000000000006c' from 'int' to 'char' inside { } [-fpermissive]

由于值是合法的,这似乎是一个错误。你能解释一下为什么我会收到这个错误以及如何解决它吗?

编辑:请注意,使用正值(例如,108)是合法的,不会导致两个编译器都出错。

【问题讨论】:

  • char 可能在目标平台上未签名。可以查一下吗?
  • @Brian,我该如何检查?
  • @AndyThomas std::is_signed<char>?或者,简单地说,char(-1) < '\0'
  • 108 是否也遇到同样的错误?此外,c++0x 的早期 GCC 实现对缩小转换非常严格。也许您的交叉编译器就是其中之一。毕竟,它intchar 的缩小转换。
  • @Barmar 使用 signed char 工作!把它写成答案,我会接受的。

标签: c++ linux c++11 cross-compiling


【解决方案1】:

char 对象(在典型的现代硬件上)可以清楚地表示所有 8 位值,因此分配这样的值应该是安全的 (*)。

如果文字是char 类型,编译器不会发出警告。 escape sequence 允许您提供十六进制数字作为字符文字:

int main(void) {
    char c[1] = {'\x94'};
}

这将在具有签名或未签名 char (example) 的系统上编译而不会触发 -Wnarrowing

(*) 这里的安全意味着不会丢失任何信息,尽管该值可能不是您所期望的:-108 如果char 是有符号的,而 148 是 char 是无符号的。

【讨论】:

    【解决方案2】:

    我在使用 crosstool-ng 的 arm 交叉编译器中编译 binutils 时遇到了类似的情况,尽管我的错误是:

    i386.cc:3165:31:错误:将“144”从“int”转换为“char”

    由于 144 大于 -128 到 127 的有符号字符范围,我不得不更改受影响的行并将函数返回为 unsigned char

    我还需要在函数的返回中使用 reinterpret_cast,因为结果被用来形成一个字符串序列。然后编译正确。

    【讨论】:

      【解决方案3】:

      这样应该会更好:

      signed char c[] = { (signed char)(-108) };
      

      因为括号中的值默认可以被视为int。

      【讨论】:

        【解决方案4】:

        当您将变量声明为char 时,无论它是有符号还是无符号,都取决于实现。如果你需要能够存储负值,你应该明确声明它signed,而不是依赖于实现定义的默认值。

        signed char c[1] = { -108 };
        

        【讨论】:

          【解决方案5】:

          因为值是合法的

          你怎么知道的? chars 签名是实现定义的。如果它是未签名的,那么您的代码会因缩小而出现格式错误 - §8.5.4/7:

          窄化转换是隐式转换
          […]
          (7.4) — 从整数类型 […] 到整数类型 不能代表原始类型的所有值,除了 其中 source 是一个常量表达式,其值在积分提升后将适合目标类型。

          §8.5.1/2:

          如果 initializer-clause 是一个表达式,并且需要一个窄化转换 (8.5.4) 来转换该表达式,则程序是非良构的。

          但是,如果您需要签名的char,请使用signed char

          signed char c[1] = {-108};
          

          …保证可以工作。

          【讨论】:

            猜你喜欢
            • 2020-06-20
            • 2020-08-21
            • 1970-01-01
            • 2021-01-02
            • 2015-09-07
            • 2014-12-04
            • 2014-01-17
            • 1970-01-01
            • 2022-07-04
            相关资源
            最近更新 更多