【问题标题】:Microsoft C++ compiler have a bug?Microsoft C++ 编译器有错误吗?
【发布时间】:2012-05-25 09:01:04
【问题描述】:
usigned int x=1;
signed int y = -1;
double z = y * x * 0.25;

我正在使用 Microsoft Visual Studio 10 C++ 编译器。 为什么 z 没有 -0.25 值? 正如我从反汇编中看到的那样,它进行有符号整数乘法(imul),将 edx 的结果放在堆栈上,并用 0! 扩展它,因为它将是一个无符号整数。之后,它使用 FP 指令将其相乘。

.............
imul        edx,dword ptr [ecx]  
mov         dword ptr [ebp-98h],edx  
mov         dword ptr [ebp-94h],0
fild        dword ptr [ebp-98h]  
fmul        qword ptr [__real@3fd0000000000000 (1402FB8h)]  
fstp        qword ptr [z]

为什么有符号*无符号相乘的结果被解释为无符号?

【问题讨论】:

  • 你在哪里看到零扩展? [ebp-94h] 与乘法的结果无关,fild 采用 dword 而不是 qword
  • 有非常具体的积分提升规则,不同的积分类型参与二元运算。我的猜测是,在那里的某个地方,正确的行为是精确的,但老实说,这是一团糟......
  • 是的,没错,怪编译器。
  • 作为一个经验法则:如果您没有丰富的 C/C++ 经验并且认为您发现了编译器错误,则意味着您自己的代码中存在错误。如果错误与隐式类型提升有关,则尤其如此。
  • 正如你所说,你使用的是 C++ 编译器,我们可以从这个问题中删除 C 标记吗?

标签: c++ visual-studio-2010 visual-c++


【解决方案1】:

表达式 y * x * 0.25 在 C 和 C++ 中都关联为 (y * x) * 0.25

unsigned intsigned int 相乘时,两个操作数都转换为unsigned int,结果也是unsigned int,这是由于C 和C++ 中算术表达式的整数转换规则,所以结果为y * x 在 C 和 C++ 中都是 UINT_MAX - 1

无论您将示例编译为 C 还是 C++,您的示例都不会出现编译器错误。

【讨论】:

  • 如果它不是编译器错误,那么在我看来,它看起来更糟糕 - C++ 规范缺陷,或者更好的说法是“规范错误”,从数学上讲,当您将负数和正数相乘时,结果肯定是负面的,那为什么要用不自然的规则来混淆工程师呢?
【解决方案2】:

这实际上是根据规范。 C++11、5.9:

许多二元运算符需要算术或 枚举类型导致转换并产生类似的结果类型 方式。目的是产生一个通用类型,这也是 结果。这种模式称为通常的算术转换, 定义如下:

[...]

否则,积分促销 (4.5) 应在两者上执行 操作数。那么以下规则应适用于推广 操作数:

[...]

  • 否则,如果无符号整数类型的操作数有秩 大于或等于另一个操作数的类型的等级, 带符号整数类型的操作数应转换为 无符号整数类型的操作数。

这里y * x中的两个操作数是有符号和无符号int,它们有一个相等的integer conversion rank;所以y 最终被转换为无符号。

【讨论】:

  • 在这种特殊情况下没有进行整体促销。
  • @Lundin:所有适用积分促销都已完成。只是在这种情况下没有一个适用。恕我直言,措辞还不错。
  • 我只是想知道你为什么引用那部分,因为它可能只会混淆 OP。
  • @Lundin:因为它是说“应适用以下规则”的部分:)
【解决方案3】:

这在标准的 [expr] 部分中有描述:

....

否则,积分促销 (4.5) 应在两者上执行 操作数。那么以下规则应适用于推广 操作数:

——如果两个操作数具有相同的类型,则不再进行转换 是需要的。

— 否则,如果两个操作数都具有有符号整数类型或 两者都有无符号整数类型,操作数的类型为 lesser 整数转换等级应转换为操作数的类型 具有更高的等级。

— 否则,如果操作数具有无符号 整数类型的等级大于或等于类型的等级 另一个操作数,带符号整数类型的操作数应为 转换为无符号整数类型的操作数的类型。

表达式从左到右求值,因此首先计算y * x。这有两种相同等级的整数类型,一种是有符号操作数,另一种是无符号操作数。因此,有符号值被转换为无符号值,如标准摘录的最后一段所述。

【讨论】:

    猜你喜欢
    • 2021-11-29
    • 2019-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-03
    • 2010-11-24
    • 2016-08-19
    • 1970-01-01
    相关资源
    最近更新 更多