今天我来了Eric Lippert的一篇文章,他试图清除运营商优先级和评估顺序之间的神话。最后有两个代码片段让我感到困惑,这是第一个片段:
int[] arr = {0};
int value = arr[arr[0]++];
现在,当我考虑变量值的值时,我只是将其计算为1。这就是我认为它的工作方式。
显然这是错误的。我试图在c#规范中搜索关于何时实际发生增量但没有找到任何增量的明确声明。
第二个片段来自Eric blog post关于主题的评论:
int[] data = { 11, 22, 33 };
int i = 1;
data[i++] = data[i] + 5;
现在我认为这个程序将执行 - 在声明数组并为i分配1之后。 [跟我一起承担]
根据我的理解,此数组现在应包含值{11, 27 ,33}。但是,当我循环打印我得到的数组值时:{11,38,33}。这意味着在解除引用数组之前发生 post 增量!
怎么会?这个帖子增量不应该发布吗?即在其他一切之后发生。
我想念的是什么人?
答案 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)
对于第一个片段,序列为:
value
。对于第二个片段,评估仍然是从左到右。
缺少的部分是“发布”并不意味着“在其他一切之后”。它只是意味着“在我检索到该变量的当前值之后立即”。在“一行代码”中间发生的后增量是完全正常的。
答案 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)
您必须分三个步骤考虑作业:
如果您有类似
的内容A().B = C()
然后首先运行A(),然后运行C(),然后运行属性设置器B.
基本上,你必须将你的陈述视为
StoreInArray(data, i++, data[i] + 5);
答案 5 :(得分:-4)
原因可能是某些编译器将i ++优化为++ i。大多数情况下,最终结果都是一样的,但在我看来,编译错误的情况很少见。
我现在无法访问Visual Studio来确认这一点,但尝试禁用代码优化并查看结果是否保持不变。