回 帖 发 新 帖 刷新版面

主题:让c语言和c++中的“a++,++a”永远不是问题

这里主要研究一下c语言和c++中的a++,++a
有分双操做数和多操做数之分
双操做数:(vc++,Turbo c)
在语言中定义a++是先用后加,++a是先加后用。
实际上对双操做数来说的是在一个语句中结束前加和后加的问题 。
即如k=(++a)+(a++);
a++是语句结束后在后加,
++a是先加后计算再语句结束。

我举几个例子(用vc反汇编说明)
1 int k=2;
int val=0;
val=(k++)+(k++);

反汇编
8:        int k=2;
00401028   mov         dword ptr [ebp-4],2//// k的地址是dword ptr [ebp-4]
9:        int val=0;    
0040102F   mov         dword ptr [ebp-8],0//val的地址是dword ptr [ebp-8]
10:       val=(k++)+(k++);
00401036   mov         eax,dword ptr [ebp-4]// 把2放入eax中
00401039   add         eax,dword ptr [ebp-4]// 把2+2=4放入eax中
0040103C   mov         dword ptr [ebp-8],eax//把eax中的4移回val中
0040103F   mov         ecx,dword ptr [ebp-4]
00401042   add         ecx,1//
00401045   mov         dword ptr [ebp-4],ecx//k地址中的值加1,k=3

00401048   mov         edx,dword ptr [ebp-4]
0040104B   add         edx,1// 寄存器中的值加1,k=4
0040104E   mov         dword ptr [ebp-4],edx//移回k地址

结论:val=*( dword ptr [ebp-8])=4;k=4

2. int k=2;
int val=0;
k=(k++)+(k++);

反汇编
:
8:        int k=2;
00401028   mov         dword ptr [ebp-4],2//同上
9:        int val=0;
0040102F   mov         dword ptr [ebp-8],0
10:       k=(k++)+(k++);
00401036   mov         eax,dword ptr [ebp-4]
00401039   add         eax,dword ptr [ebp-4] //同上
0040103C   mov         dword ptr [ebp-4],eax//同上,不同的是计算结果存入k地址k=4
0040103F   mov         ecx,dword ptr [ebp-4]
00401042   add         ecx,1//寄存器中的值加1,
00401045   mov         dword ptr [ebp-4],ecx//k=5
00401048   mov         edx,dword ptr [ebp-4]
0040104B   add         edx,1//寄存器中的值加1
0040104E   mov         dword ptr [ebp-4],edx//k=6

结论:k=*( dword ptr [ebp-4])=6;

3 int k=2;
int val=0;
val=(++k)+(++k);

反汇编:
8:        int k=2;
00401028   mov         dword ptr [ebp-4],2// k的地址是dword ptr [ebp-4]
9:        int val=0;
0040102F   mov         dword ptr [ebp-8],0//val的地址是dword ptr [ebp-8]
10:       val=(++k)+(++k);//k先加
00401036   mov         eax,dword ptr [ebp-4]
00401039   add         eax,1//寄存器中的值加1

0040103C   mov         dword ptr [ebp-4],eax//k=3
0040103F   mov         ecx,dword ptr [ebp-4]
00401042   add         ecx,1//对k地址中的值加1,k=4
00401045   mov         dword ptr [ebp-4],ecx
00401048   mov         edx,dword ptr [ebp-4]
0040104B   add         edx,dword ptr [ebp-4]//k+k=8
0040104E   mov         dword ptr [ebp-8],edx//值移入val地址中val=8

结论:val=*( dword ptr [ebp-8])=8;k=4
4. int k=2;
int val=0;
k=(++k)+(++k);
反汇编:
8:        int k=2;
00401028   mov         dword ptr [ebp-4],2
9:        int val=0;
0040102F   mov         dword ptr [ebp-8],0
10:       k=(++k)+(++k);
00401036   mov         eax,dword ptr [ebp-4]
00401039   add         eax,1
0040103C   mov         dword ptr [ebp-4],eax
0040103F   mov         ecx,dword ptr [ebp-4]
00401042   add         ecx,1
00401045   mov         dword ptr [ebp-4],ecx
00401048   mov         edx,dword ptr [ebp-4]
0040104B   add         edx,dword ptr [ebp-4]///以上同3例
0040104E   mov         dword ptr [ebp-4],edx// 值移入k地址k=8
结论:k=*( dword ptr [ebp-4])=8;

5. int k=2;
int val=0;
val=(++k)+(k++);

反汇编:


8:        int k=2;
00401028   mov         dword ptr [ebp-4],2
9:        int val=0;
0040102F   mov         dword ptr [ebp-8],0
10:       val=(++k)+(k++);
00401036   mov         eax,dword ptr [ebp-4]
00401039   add         eax,1
0040103C   mov         dword ptr [ebp-4],eax//k=k+1=3
0040103F   mov         ecx,dword ptr [ebp-4]
00401042   add         ecx,dword ptr [ebp-4]//k+k=6
00401045   mov         dword ptr [ebp-8],ecx//val=6
00401048   mov         edx,dword ptr [ebp-4]
0040104B   add         edx,1//k=k+1=4
0040104E   mov         dword ptr [ebp-4],edx

结论:val=*( dword ptr [ebp-8])=6;k=4

6. int k=2;
int val=0;
k=(++k)+(k++);

反汇编:

8:        int k=2;
00401028   mov         dword ptr [ebp-4],2
9:        int val=0;
0040102F   mov         dword ptr [ebp-8],0
10:       k=(++k)+(k++);
00401036   mov         eax,dword ptr [ebp-4]
00401039   add         eax,1//k+1
0040103C   mov         dword ptr [ebp-4],eax//k=3
0040103F   mov         ecx,dword ptr [ebp-4]
00401042   add         ecx,dword ptr [ebp-4]//k+k=6
00401045   mov         dword ptr [ebp-4],ecx//k=6
00401048   mov         edx,dword ptr [ebp-4]
0040104B   add         edx,1
0040104E   mov         dword ptr [ebp-4],edx//k=k+1=7

结论:k=*( dword ptr [ebp-4])=7;k=7

多操做数(vc++)
(Turbo c多操做数与两个操做数一样,由于编译器位数不同)


多操做数(>2)头两个操做数同以上(中间值)而后面的数如是(++i)加1
如是(i++)不加1。赋值给变量如果不是本身则结束
如果是本身则要数(i++)个数如是n加n
举几个例子(用vc反汇编说明)
1.
int k=2;
int val=0;
val=(k++)+(k++)+(++k);

反汇编:

331:  int k=2;
00407488   mov         dword ptr [ebp-14h],2
332:  int val=0;
0040748F   mov         dword ptr [ebp-18h],0
333:  val=(k++)+(k++)+(++k);
00407496   mov         eax,dword ptr [ebp-14h]
00407499   add         eax,dword ptr [ebp-14h]//以上同双操做数中间数存在eax中eax=4,k=2
0040749C   mov         ecx,dword ptr [ebp-14h]
0040749F   add         ecx,1
004074A2   mov         dword ptr [ebp-14h],ecx//k=3
004074A5   add         eax,dword ptr [ebp-14h]//eax+k=
004074A8   mov         dword ptr [ebp-18h],eax//赋值给val=eax+k=7
004074AB   mov         edx,dword ptr [ebp-14h]
004074AE   add         edx,1
004074B1   mov         dword ptr [ebp-14h],edx
004074B4   mov         eax,dword ptr [ebp-14h]
004074B7   add         eax,1
004074BA   mov         dword ptr [ebp-14h],eax

结论:val=*( dword ptr [ebp-18h])=6;k=5

2.
int k=2;
int val=0;
k=(k++)+(k++)+(++k);
反汇编:


331:  int k=2;
00407488   mov         dword ptr [ebp-14h],2
332:  int val=0;
0040748F   mov         dword ptr [ebp-18h],0
333:  k=(k++)+(k++)+(++k);
00407496   mov         eax,dword ptr [ebp-14h]
00407499   add         eax,dword ptr [ebp-14h]
0040749C   mov         ecx,dword ptr [ebp-14h]
0040749F   add         ecx,1
004074A2   mov         dword ptr [ebp-14h],ecx
004074A5   add         eax,dword ptr [ebp-14h]
004074A8   mov         dword ptr [ebp-14h],eax//赋值给k=eax+k=7
004074AB   mov         edx,dword ptr [ebp-14h]
004074AE   add         edx,1
004074B1   mov         dword ptr [ebp-14h],edx//k=k+1=8
004074B4   mov         eax,dword ptr [ebp-14h]
004074B7   add         eax,1
004074BA   mov         dword ptr [ebp-14h],eax//k=k+1=9

结论:val=*( dword ptr [ebp-14h])=9;

举个题(vc++下)
1.
int  k=2;
int  val =0;
val=(++k)+(++k)+(k++)+(++k) +(++k) +(++k) +(++k) +(k++)+(k++)+(k++);
val=4   +    4 +4    +5     +6     +7     +8     +8    +8     +8= 62

2.
int  k=2;
int  val =0;
k=(++k)+(++k)+(k++)+(++k) +(++k) +(++k) +(++k) +(k++)+(k++)+(k++);
4个k++
k=4   +    4+  4   +5     +6    + 7    +  8    +8    +8    +8  在加  4=66

在Turbo c 下

1.
int  k=2;
int  val =0;
val=(++k)+(++k)+(k++)+(++k) +(++k) +(++k) +(++k) +(k++)+(k++)+(k++);
6个++k,4个(k++)
6个++k运行后k=8,val=8*10=80;结束

2.
int  k=2;
int  val =0;
k=(++k)+(++k)+(k++)+(++k) +(++k) +(++k) +(++k) +(k++)+(k++)+(k++);
6个++k,k=80
4个(k++),k=80+4=84;

"a--,--a"与++a,a++相同

回复列表 (共14个回复)

11 楼

研究这种无聊的问题有什么意义?对于超出标准的用法,编译器设计者想怎么处理就可以怎么处理,生城什么样的目标代码取决于他的习惯和风格。正如楼上有人问为什么TC,vC的输出不一样,理由很简单:微软的程序员想这样设计,Borland的程序员想那样设计。和你那所谓的“编译器位数”扯不上一点关系,少在这儿误人子弟。有这么多闲时间建议你去研究算法,去看设计模式,去写程序, 比这有意义一千倍!

12 楼

呵呵,不瞒你说,我写了这么多年代码,还帮别人调试了几百个程序,至于局部预测性,控制自己的程序好像还靠不上这些东西。楼上的也不要这么偏激,研究什么是人家的爱好,没什么大不了的,我以前也喜欢研究类似的东西,不说有什么意义,至少也是一种乐趣。

13 楼

我对汇编绝无兴趣,不过汇编搞病毒到是一流,呵呵.
C语言中每一个运算都是一个函数,A++和++A也不例外,在函数内部看好是做了什么和返回什么就可以了,A++是把A值加上1,然后返回原来A的值,不过,可不是A的引用,++A加完了,返回A的引用,这就是一个区别吧.
至于编译器的问题,那是求值顺序的问题,
  看下边的,
a=1;
a++++++;a是2
a=1;
++++++a;a是4;
a=1;
a+++++a;a是3,会做(a++)+(++a);,不过,这个可有问题,后面的量改变时,可能会改变前面的比如,要是先算(++a),那么会把前一个a的值改变,编译器的不同会造成求值顺序的不同;(在清华大学的C++程序设计的书上有介绍,好像是第4章还是第5章了,我也记不好了)

14 楼

顶一下cybergate所说的“绝对不要做出超出C/C++标准的事情,否则运行结果就是不可预测。”。

我来回复

您尚未登录,请登录后再回复。点此登录或注册