int [] arr = {0}; int value = arr [arr [0] ++];值= 1?

时间:2009-08-11 13:07:22

标签: c# operator-precedence

今天我来了Eric Lippert的一篇文章,他试图清除运营商优先级和评估顺序之间的神话。最后有两个代码片段让我感到困惑,这是第一个片段:

      int[] arr = {0};
      int value = arr[arr[0]++];

现在,当我考虑变量值的值时,我只是将其计算为1。这就是我认为它的工作方式。

  1. 首先将arr声明为int数组 里面有一个项目;这个 item的值为0.
  2. 第二个得到arr [0] -0的值 这种情况。
  3. 第三个得到arr的值[值 步骤2](仍然是0) - 指 arr [0]再次--still 0。
  4. 第四步指定第3步的值 (0)到变量值。 --value = 0现在
  5. 添加到步骤2的值1 - 现在 arr [0] = 1。
  6. 显然这是错误的。我试图在c#规范中搜索关于何时实际发生增量但没有找到任何增量的明确声明。
    第二个片段来自Eric blog post关于主题的评论:

     int[] data = { 11, 22, 33 }; 
     int i = 1;
     data[i++] = data[i] + 5;
    

    现在我认为这个程序将执行 - 在声明数组并为i分配1之后。 [跟我一起承担]

    1. 获取数据[i] --1
    2. 将值添加到步骤1的值 5 - 6
    3. 分配给数据[i](仍为1) 步骤2的值--data [i] = 6
    4. 增量i - i = 2
    5. 根据我的理解,此数组现在应包含值{11, 27 ,33}。但是,当我循环打印我得到的数组值时:{11,38,33}。这意味着在解除引用数组之前发生 post 增量!
      怎么会?这个帖子增量不应该发布吗?即在其他一切之后发生。
      我想念的是什么人?

6 个答案:

答案 0 :(得分:17)

后增量操作作为评估整体表达的一部分发生。这是在评估值之后但在评估任何其他表达式之前发生的副作用。

换句话说,对于任何表达式E,E ++(如果合法)表示类似(伪代码):

T tmp = E;
E += 1;
return tmp;

在评估E ++之前,这是所有部分。

有关详细信息,请参阅C#3.0规范的第7.5.9节。


此外,对于将LHS归类为变量的分配操作(如本例所示),在评估RHS

之前评估LHS

所以在你的例子中:

int[] data = { 11, 22, 33 }; 
int i = 1;
data[i++] = data[i] + 5;

相当于:

int[] data = { 11, 22, 33 }; 
int i = 1;
// Work out what the LHS is going to mean...
int index = i;
i++;
// We're going to assign to data[index], i.e. data[1]. Now i=2.

// Now evaluate the RHS
int rhs = data[i] + 5; // rhs = data[2] + 5 == 38

// Now assign:
data[index] = rhs;

规范的相关部分是第7.16.1节(C#3.0规范)。

答案 1 :(得分:5)

对于第一个片段,序列为:

  1. 如你所述声明arr:
  2. 检索arr [0]的值,即0
  3. 将arr [0]的值增加到1。
  4. 检索arr [(#2的结果)]的值,即arr [0],(每#3)为1。
  5. 将结果存储在value
  6. value = 1
  7. 对于第二个片段,评估仍然是从左到右。

    1. 我们在哪里存储结果?在data [i ++]中,它是data [1],但现在i = 2
    2. 我们添加了什么? data [i] + 5,现在是数据[2] + 5,即38。
    3. 缺少的部分是“发布”并不意味着“在其他一切之后”。它只是意味着“在我检索到该变量的当前值之后立即”。在“一行代码”中间发生的后增量是完全正常的。

答案 2 :(得分:2)

data[i++] // => data[1], then i is incremented to 2

data[1] = data[2] + 5 // => 33 + 5

答案 3 :(得分:0)

我希望后增量运算符在使用其值后递增变量。 在这种情况下,变量在第二次引用变量之前递增。

如果不是这样,你可以写

data[i++] = data[i++] + data[i++] + data[i++] + 5

如果你说的话,你可以删除增量运算符,因为它在我报告的指令中没有做任何事情。

答案 4 :(得分:0)

您必须分三个步骤考虑作业:

  1. 评估左侧(=获取应存储值的地址)
  2. 评估右侧
  3. 将步骤2中的值分配给步骤1中的内存位置。
  4. 如果您有类似

    的内容
    A().B = C()
    

    然后首先运行A(),然后运行C(),然后运行属性设置器B.

    基本上,你必须将你的陈述视为

    StoreInArray(data, i++, data[i] + 5);
    

答案 5 :(得分:-4)

原因可能是某些编译器将i ++优化为++ i。大多数情况下,最终结果都是一样的,但在我看来,编译错误的情况很少见。

我现在无法访问Visual Studio来确认这一点,但尝试禁用代码优化并查看结果是否保持不变。