调试工具:Visual C++ 6.0在一个源文件中输入如下代码:#include <iostream.h>
void main() {
int i = 3;
int m = (++i) + (++i) + (++i);
cout << i << endl;
cout << m << endl;
}这个程序非常简单,看了以后,你心里肯定已经有了答案(6,15),但上机调试的结果变量 m 却不是那个答案。有哪位高手知道这是为什么吗?有兴趣的可以讨论讨论。
void main() {
int i = 3;
int m = (++i) + (++i) + (++i);
cout << i << endl;
cout << m << endl;
}这个程序非常简单,看了以后,你心里肯定已经有了答案(6,15),但上机调试的结果变量 m 却不是那个答案。有哪位高手知道这是为什么吗?有兴趣的可以讨论讨论。
int i = 3;
int m = (++i) + (++i) + (++i);
等效于:
int n = (++i) + (++i); //i = 5, n = 10
int m = n + (++i); //i = 6, m = 16TC中可能是这个答案
int m = (++i) + (++i) + (++i);//i = 6, m = 18;
int i = 3; int i = 3;
int n = (i++) + (++i); int m = (i++) + (++i) + (++i);
int m = n + (++i); cout << i << endl;
cout << i << endl; cout << m << endl;
cout << m << endl; }
}左边的 m = 14, 而右边的 m = 13。(第一个 ++i 改成了 i++)有谁知道为什么?
n = 4 + 4 = 8
m = 8 + 6 = 14右边的:
m = 4+4+5 = 13 因为i++的原因,第一次加法只有加了1次i,就是4+4,然后第二次再加1,结果是8+5,加法完毕后才执行,最后的把i+1,而所比的情况由于分为了2个表达式,因此 第二次加法的时候i已经是5了
当不能等效于
int n = (i++) + (++i);
int m = n + (++i); 因为i++是要等整个式子计算完后才自加的,所以等效式子是:
int n = (i) + (++i);
int m = n + (++i);
i++;
***********
#include <iostream.h>
void main() {
int i = 3;
int m = (++i) + (++i) + (++i);
cout << i << endl;
cout << m << endl;
}
*********** 编译器在处理(++i) + (++i) + (++i)的时候,从编译原理的角度分析,首先接受的是表达式最左边的“(”,这在所有的操作符里是优先级最高的!所以无论后面的进行何种计算,都不考虑,只管先处理完当前括号中的内容。 那么先处理完第一个(++i),处理的结果是4,但是——这里的中间结果,并不是另外赋给一个临时变量,而是保存在变量“i”里,当前的结果为4。假定这第一个(++i)的处理结果是保存到一个独立的临时变量里,在表达式的处理过程中不再变化的话,那么按我们常规的数学逻辑看,就不会有后来的奇怪现象。可实际上这第一个被处理的(++i)处理之后的值依然保存在变量“i”里,在编译器处理第二个(++i)后,变量“i”发生改变,也就是改变了第一个加法项(把第一个(++i)的计算结果作为一个完整加法项看待)的结果,那么导致了实际结果与数学逻辑相悖的结果。 我再描述一下中间过程: 先看人工认知的数学逻辑,先算第一个(++i),得到4+x,再算第二个(++i),应该是4+5+y,算出最后一个(++i)时,最后结果就是4+5+6=15。 机器的算法(假定多个加法项的计算顺序是从左到右):先算第一个(++i),得到i+x,此时变量i里存的是4,没问题。再算第二个(++i),得到i+i+y,此时i里存的是5,问题就出在这里,算出第二个加法项结果的同时,该变了第一个加法项的结果,本来从数学逻辑的角度,两个加法项的值不应该互相干扰的,问题就在于两个加法项共用了同一个变量保存结果。所以最终结果比正常数学逻辑多出来的1就是第一个加法项被干扰的结果。算完第二个(++i)后,判断后面的也是加法,于是先合并了前两个加法项,就是i+i,得到10,这个结果可没有再保存到i中,而是由专门的临时变量保存。继续,该计算第三个(++i),得到10+6,最后就变成16了。 补充,如果编译器对多个加法项的计算顺序不是从左到右而是相反,那么最终就成了6+6+6=18。(由此也可以判断VC的编译器对连续加法项的处理顺序是从左到右的。) **************事后感:
1、对(++i) + (++i) + (++i)的处理,我觉得暴露了VC编译器的一个不足。表达式的计算应该符合数学逻辑,VC对此的处理显然并不合理。如果每个加法项的最终结果都由另外的临时变量保存,就严格切合数学逻辑了。
2、类似(++i) + (++i) + (++i)这样的写法,也就是作为理论研究可以探讨一下,实际工程里要绝对避免这种不明朗的写法。
3、根据我的分析再设计个更简单的问题,i + (++i)会得到8而不是7!(i初值还是3)
00401058 mov dword ptr [ebp-4],3
6: int m = (++i) + (++i) + (++i);
0040105F mov eax,dword ptr [ebp-4]
00401062 add eax,1
00401065 mov dword ptr [ebp-4],eax
00401068 mov ecx,dword ptr [ebp-4]
0040106B add ecx,1
0040106E mov dword ptr [ebp-4],ecx
00401071 mov edx,dword ptr [ebp-4]
00401074 add edx,dword ptr [ebp-4]
00401077 mov eax,dword ptr [ebp-4]
0040107A add eax,1
0040107D mov dword ptr [ebp-4],eax
00401080 add edx,dword ptr [ebp-4]
00401083 mov dword ptr [ebp-8],edx