【问题标题】:Implicit type conversion and different behavior between x64 and arm64x64 和 arm64 之间的隐式类型转换和不同行为
【发布时间】:2021-07-20 16:22:47
【问题描述】:

在 arm64 上测试我的软件时遇到了一个奇怪的问题。

我写了一些代码来重现这个问题:

char c;
int sum = 0;
for (int i = 0; i <= 255; i++)
{
   c = i;
   int a = c * 10;
   sum += a;
   std::cout << a << std::endl;
}

当我在 Windows(使用 Visual Studio 2017 构建)或 Ubuntu x64(gcc 9.3.0-17)上运行它时,我得到以下结果:

0
10
...
1260
1270
-1280
-1270
-20
-10
sum=-1280

如果我在 Ubuntu arm64 (gcc 9.3.0-17) 上运行相同的代码,我会得到不同的结果:

0
10
...
1260
1270
1280
1290
...
2540
2550
sum=326400

我不知道在 arm64 上的 gcc 中是否有一些额外的优化(使用 -O3)或者是否有一些我看不到的问题?关于如何解决此问题的任何想法?

【问题讨论】:

  • 也许你应该在arm平台上检查char是有符号还是无符号类型,而不是假设它。请注意,char 是与 signed charunsigned char 不同的类型。
  • 不是硬件;决定签名和溢出行为的是编译器。
  • @alfC 我认为 OP 已经 not 首先转换为 int,以便重现该问题。他们的“现实世界”代码可能更加微妙/复杂。
  • @alfC 另外,在您的建议中,static_cast&lt;int&gt;(c) 为时已晚 - 之前的语句中已经发生了赋值和(可能)溢出。
  • char 可以是有符号或无符号的,在 ARM 上通常默认为无符号,而大多数架构默认使用有符号字符:Why unsigned types are more efficient in arm cpu?Is char signed or unsigned by default?is char signed or unsigned by default on iOS?。在 gcc 中,可以使用 -funsigned-char-fsigned-char 更改 char 的符号

标签: c++ gcc arm


【解决方案1】:

char 数据类型可以是 signedunsigned。在前者的情况下(似乎是针对 x64 的情况),c = i 语句将在for 循环的第 129th 次迭代中导致溢出(a 的最大值signed char 是 127) 并且分配给它的值已“环绕”为负值。

但是,当面向 arm64 时,您的编译器似乎使用 unsigned char 类型(范围为 0255),因此该语句中没有溢出,并且算术“按预期”进行。


要确认(或以其他方式)上述诊断,只需检查不同构建环境中CHAR_MAX 常量(在&lt;climits&gt; 头文件中定义)的值。

【讨论】:

  • 这正是问题所在! char 默认情况下是无符号的。感谢您指出了这一点。我今天学到了一些东西。
【解决方案2】:

char 按标准签名。
然而,ARM 决定在几十年前默认将其设为无符号。

就这么简单。

【讨论】:

  • C++ 标准让它实现定义char 是有符号还是无符号:[basic.fundamental (7)]。 ARM 在这里完全兼容。
  • @NateEldredge char 在 ARM 的所有工具链上均未签名。这是 ARM 的决定。
  • 当然。我不同意你的第一句话,char 是“按标准”签名的。
  • @NateEldredge 你是对的。我不得不承认这对我来说是新的。
【解决方案3】:

char 用 8 位表示,并且是有符号的。在第一位被解释为负数之后,您可以存储 0-127。也许最好使用uint8_t 或类似的而不是char

【讨论】:

  • 您不能将 128 存储在有符号的 8 位字符类型中。范围是 -128 到 +127。
  • 你知道编辑自己的帖子,对吧?
  • char is represented by 8 bit and it is signed 不正确charCHAR_BIT 位(可以大于 8)表示,并且是有符号或无符号类型,具体取决于实现。而且您的回答没有解释为什么两个平台之间的结果不同
  • 溢出不是问题,在这种情况下甚至是有意的。 Windows 和 Linux x64 行为正确。并且无法更改代码,它的使用范围太广。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多