为什么VB.NET和C ++为同一个表达式提供不同的结果?

时间:2014-07-30 07:12:47

标签: c++ vb.net operators

请考虑以下代码段:

C ++:

#include <iostream>
using namespace std;

int main()
{
   int x = 10, y = 20;
   y = x + (x=y)*0;
   cout << y;
   return 0;
}

,其结果为20,因为y的值已分配给x,因为根据Operator Precedence Table首先执行括号。

VB.NET:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
   Dim x As Integer = 10
   Dim y As Integer = 20
   y = x + (x = y) * 0
   MsgBox(y)
End Sub

而是给出10的结果。

  • 造成这种差异的原因是什么?
  • VB.NET中运算符的执行顺序是什么?

3 个答案:

答案 0 :(得分:5)

与C ++不同,VB.NET的=并不总是一项任务。如果它出现在表达式中,它也可以是等式比较运算符(C ++中的==)。因此你的两个表达方式是不一样的。它们甚至不相同。 VB.NET代码没有你想象的那样。

首先是你的C ++代码:就像你说的那样,作业x=y首先出现;因此,你的代码大致相当于:(似乎不正确;请参阅Jens' answer。)由于你最终y20,很可能是你的C ++编译器评估了您的代码,就像您编写了这样:

int x = 10, y = 20;
x = y;
y = x + x*0; // which is equivalent to `y = 20 + 20*0;`, or `y = 20 + 0;`, or `y = 20;`

然而,在VB.NET中,因为子表达式=中的(x=y)实际上并未被解释为赋值,但作为比较,代码等同于:

Dim x As Integer = 10
Dim y As Integer = 20
y = 10 + False*0 ' which is equivalent to `y = 10 + 0*0`, or `y = 10` '

这里,运算符优先级甚至没有发挥作用,而是将布尔值False隐式类型转换为数字0

(以防万一你想知道:在VB.NET中,表达式中的赋值是不可能的。赋值必须始终是它们自己的完整语句,它们不能“内联”发生。否则就无法判断是否{表达式中的{1}}表示赋值或比较,因为两者都使用相同的运算符。)

答案 1 :(得分:4)

您的C ++代码段是未定义的行为。使用x作为第一个参数并将y赋值给x之间没有序列点,因此编译器可以按任何顺序计算子表达式。两个

  1. 首先评估左侧:y = 10 +(x = y)* 0 - > y = 10 +(x = 20)* 0 - > y = 10 + 20 * 0
  2. 首先评估右侧:y = x +(x = 20)* 0 - > y = 20 + 20 * 0
  3. 在表达式中放置赋值通常也是一种非常糟糕的风格。

答案 2 :(得分:4)

这个答案仅作为评论,但其长度很快就超出了限制。对不起:)

您将运算符优先级评估顺序混淆。 (这是一种非常普遍的现象,所以不要感觉不好)。让我试着用更简单的例子来解释更熟悉的算子:

如果你有一个像a + b * c这样的表达式,那么乘法将始终在加法之前发生,因为* 运算符+ <更紧密地绑定EM>运算符的。到现在为止还挺好?重要的是,允许C ++以任何顺序评估操作数 abc。如果其中一个操作数具有影响另一个操作数的副作用,那么这有两个原因:

  1. 可能会导致未定义的行为(在您的代码中确实如此),更重要的是
  2. 保证为您的代码的未来读者带来严重的麻烦。 所以请不要这样做!
  3. 顺便说一句,Java总是首先评估a,然后评估b,然后评估c,“尽管”在添加之前发生了乘法。伪字节码看起来像push a; push b; push c; mul; add;

    (你没有问过Java,但是我想提一下Java来举例说明评估a不仅可行,而且语言规范保证 .C#表现得很好同样的方式。)

相关问题