调试工具: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 却不是那个答案。有哪位高手知道这是为什么吗?有兴趣的可以讨论讨论。

解决方案 »

  1.   

    vc中得到的答案是(6,16)原因是因为VC是分段计算的
    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;
      

  2.   

    分段计算? 好像不对吧!请看如下两个程序:#include <iostream.h>void main() {                       void main() {
        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++)有谁知道为什么?
      

  3.   

    左边的:
    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了
      

  4.   

    m = (i++) + (++i) + (++i);
    当不能等效于
    int n = (i++) + (++i);
    int m = n + (++i); 因为i++是要等整个式子计算完后才自加的,所以等效式子是:
    int n = (i) + (++i);
    int m = n + (++i); 
    i++;
      

  5.   

    服了,小问题扯出VC内部处理方式了。按说计算m = (++i) + (++i) + (++i)的时候,从优先级的角度,自然是先算括号内的,三个加法项无论从左加到右还是从右加到左应该不影响结果。居然得到16?!期待权威解释。
      

  6.   

    我终于想到一个合理的解释了:仅针对如下代码:
    ***********
    #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)
      

  7.   

    谢谢楼上的朋友,不过根据你的推论,m = (i++) + (++i) + (++i) 似乎怎么也不等于 13 那。问 phoenix96_2000(eXMe):    "...... 加了 1 次 i, 就是 4 + 4, 然后第二 ......" 这个理由未免太过于勉强了吧?第一个 i 不管你取什么,到第二项,必定要经过两次 自加运算的耶!怎么能说是 4 + 4 呢?这个结论从何而来?
      

  8.   

    这种问题,多说无益,VC到底是怎么做的,自己看汇编出来的代码吧5:        int 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