int arr = {0}; int value = arr ++]; 值= 1?
今天我来了Eric Lippert的一篇文章,他试图清除运营商优先级和评估顺序之间的神话。 最后有两个代码片段让我困惑,这是第一个片段:
int[] arr = {0}; int value = arr[arr[0]++];
现在,当我考虑变量值的值时,我只是将其计算为1。 这就是我认为它的工作方式。
- 首先将arr声明为int数组,其中包含一个项目; 这个项目的值是0。
- 在这种情况下,第二个得到arr [0] –0的值。
- 第三个得到arr的值[步骤2的值](仍为0) – 再次设置arr [0] – 仍然为0。
- 第四步将步骤3(0)的值赋给变量值。 –value = 0现在
- 添加到步骤2的值1 – 现在arr [0] = 1。
显然这是错误的。 我试图在c#规范中搜索关于何时实际发生增量的一些明确陈述,但没有找到任何增量。
第二个片段来自Eric关于该主题的博客文章的评论:
int[] data = { 11, 22, 33 }; int i = 1; data[i++] = data[i] + 5;
现在这是我认为该程序将执行的方式 – 在声明数组并为i分配1之后。 [跟我一起]
- 获取数据[i] –1
- 将值5 – 6添加到步骤1的值
- 分配给data [i](仍为1)步骤2的值–data [i] = 6
- 增量i – i = 2
根据我的理解,这个数组现在应该包含值{11,27,33}。 但是,当我循环打印我得到的数组值时:{11,38,33}。 这意味着在取消引用数组之前发生了增量!
怎么会? 这个post增量不应该发布吗? 即发生在其他一切之后。
我想念的是什么人?
后增量操作作为评估整体表达的一部分发生。 这是在评估值之后但在评估任何其他表达式之前发生的副作用。
换句话说,对于任何表达式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], ie 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规范)。
对于第一个片段,序列是:
- 如你所述声明arr:
- 检索arr [0]的值,即0
- 将arr [0]的值增加到1。
- 检索arr [(#2的结果)]的值,即arr [0],(每#3)为1。
- 存储导致
value
。 - 值= 1
对于第二个片段,评估仍然是从左到右。
- 我们在哪里存储结果? 在data [i ++]中,它是数据[1],但现在i = 2
- 我们加什么? data [i] + 5,现在是数据[2] + 5,即38。
缺少的部分是“post”并不意味着“在其他所有事情之后”。 它只是意味着“在我检索到该变量的当前值之后立即”。 在“一行代码”中间发生的后增量是完全正常的。
data[i++] // => data[1], then i is incremented to 2 data[1] = data[2] + 5 // => 33 + 5
我希望后增量运算符在使用其值后递增变量。 在这种情况下,变量在第二次引用变量之前递增。
如果不是这样,你可以写
data[i++] = data[i++] + data[i++] + data[i++] + 5
如果它就像你说的那样,你可以删除增量运算符,因为它在我报告的指令中实际上没有做任何事情。
您必须分三个步骤考虑作业:
- 评估左侧(=获取应存储值的地址)
- 评估右侧
- 将步骤2中的值分配给步骤1中的内存位置。
如果你有类似的东西
A().B = C()
然后首先运行A(),然后运行C(),然后运行属性设置器B.
从本质上讲,你必须将你的陈述视为
StoreInArray(data, i++, data[i] + 5);
原因可能是某些编译器将i ++优化为++ i。 大多数情况下,最终结果是相同的,但在我看来,这是编译器错误的罕见情况之一。
我现在无法访问Visual Studio来确认这一点,但尝试禁用代码优化并查看结果是否保持不变。