陈皓专栏 【空谷幽兰,心如皓月】

芝兰生于深谷,不以无人而不芳;君子修道立德,不为困穷而改节。

用户操作
[即时聊天] [发私信] [加为好友]
陈皓
陈皓的公告
Email & MSN
haoel@hotmail.com


本博客中所有文章均为本作者原创发表,请勿用于商业用途。如需转载,请注明作者和出处。
最近评论
John:““make clean”将清除所有要被清除的文件”
这个命令当为笔误,应该是make cleanall作所有的清除。因为cleanall是被定义的伪目标,而clean并没有被定义。
救援隊募集:アダルトエロ不倫
hooked:不错,哈哈。dexingchen兄完全没有明白楼主的用意啊。
原代码中有点小错误,比如“Fun = (Fun)pVtab[s][1];”,应该是“pFun = (Fun)pVtab[s][1];”,最后一个图中,第三个虚表里的Base2应该是Base3

另外,如果把“typedef void(*Fun)(void);”改成“typedef void(*Fun)……
hooked:不错,哈哈。dexingchen兄完全没有明白楼主的用意啊。
原代码中有点小错误,比如“Fun = (Fun)pVtab[s][1];”,应该是“pFun = (Fun)pVtab[s][1];”,最后一个图中,第三个虚表里的Base2应该是Base3

另外,如果把“typedef void(*Fun)(void);”改成“typedef void(*Fun)……
wanhongtan:I like the article
i turn it
OK
文章分类
收藏
    相册
    我的BLOG
    耗子小筑(非技术)(RSS)
    陈皓专栏(技 术)(RSS)
    存档
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 Inside i++收藏

    新一篇: 编程修养(一) | 旧一篇: 用C写有面向对象特点的程序


    i++、++i、i=i+1、效率怎么样?看过一本书上说,i++比i=i+1好
    的地方是因为i=i+1中的那个1要占用一个寄存器,所以速度没有
    i++快,于是我想验证一下。另外,以前听说过Java中的“i=i++”
    得不到正确结论,也就是应该是“先累加再赋值”,但Java经过这
    种运算后,i值居然没有变化。所以在这里,想一并把这几个问题
    在C中验证一下。


    =====================测试的C源程序====================

     #01: #include <stdio.h>
     #02:
     #03: main()
     #04: {
     #05:  int i=0, j=0;
     #06:  i=i++;
     #07:
     #08:  i=i+1;
     #09:  i++;
     #10:  ++i;
     #11:
     #12:  j=i+1;
     #13:  j=i++;
     #14:  j=++i;
     #15:
     #16:  printf("i=%d", i);
     #17: }

    ======================================================

    下面是我在 VC++ 6.0 + SP5 / Window 2000环境下对上述源程序的反汇编:

    5:        int i=0, j=0;
    0040D698   mov         dword ptr [ebp-4],0
    0040D69F   mov         dword ptr [ebp-8],0

    6:        i=i++;
    0040D6A6   mov         eax,dword ptr [ebp-4]
    0040D6A9   mov         dword ptr [ebp-4],eax
    0040D6AC   mov         ecx,dword ptr [ebp-4]
    0040D6AF   add         ecx,1
    0040D6B2   mov         dword ptr [ebp-4],ecx

    8:        i=i+1;
    0040D6B5   mov         edx,dword ptr [ebp-4]
    0040D6B8   add         edx,1
    0040D6BB   mov         dword ptr [ebp-4],edx

    9:        i++;
    0040D6BE   mov         eax,dword ptr [ebp-4]
    0040D6C1   add         eax,1
    0040D6C4   mov         dword ptr [ebp-4],eax

    10:       ++i;
    0040D6C7   mov         ecx,dword ptr [ebp-4]
    0040D6CA   add         ecx,1
    0040D6CD   mov         dword ptr [ebp-4],ecx

    12:       j=i+1;
    0040D6D0   mov         edx,dword ptr [ebp-4]
    0040D6D3   add         edx,1
    0040D6D6   mov         dword ptr [ebp-8],edx

    13:       j=i++;
    0040D6D9   mov         eax,dword ptr [ebp-4]
    0040D6DC   mov         dword ptr [ebp-8],eax
    0040D6DF   mov         ecx,dword ptr [ebp-4]
    0040D6E2   add         ecx,1
    0040D6E5   mov         dword ptr [ebp-4],ecx

    14:       j=++i;
    0040D6E8   mov         edx,dword ptr [ebp-4]
    0040D6EB   add         edx,1
    0040D6EE   mov         dword ptr [ebp-4],edx
    0040D6F1   mov         eax,dword ptr [ebp-4]
    0040D6F4   mov         dword ptr [ebp-8],eax


    =================================================================

    下面是我在 SCO UNIX下用cc -g 对上述源程序编译后,用dbx打出的内存汇编代码:

    ( int i=0, j=0; )
    0x0000015e (main:5)            mov       DWord Ptr [ebp-0x04],$0
    0x00000165 (main:5)            mov       DWord Ptr [ebp-0x08],$0

    ( i=i++; )
    0x0000016c (main:6)            mov       eax,DWord Ptr [ebp-0x04]
    0x0000016f (main:6)            inc       DWord Ptr [ebp-0x04]
    0x00000172 (main:6)            mov       DWord Ptr [ebp-0x04],eax

    ( i=i+1; )
    0x00000175 (main:8)            inc       DWord Ptr [ebp-0x04]

    ( i++; )
    0x00000178 (main:9)            inc       DWord Ptr [ebp-0x04]

    ( ++i; )
    0x0000017b (main:10)           inc       DWord Ptr [ebp-0x04]

    ( j=i+1; )
    0x0000017e (main:12)           mov       eax,DWord Ptr [ebp-0x04]
    0x00000181 (main:12)           inc       eax
    0x00000182 (main:12)           mov       DWord Ptr [ebp-0x08],eax

    ( j=i++; )
    0x00000185 (main:13)           mov       eax,DWord Ptr [ebp-0x04]
    0x00000188 (main:13)           inc       DWord Ptr [ebp-0x04]
    0x0000018b (main:13)           mov       DWord Ptr [ebp-0x08],eax

    ( j=++i; )
    0x0000018e (main:14)           inc       DWord Ptr [ebp-0x04]
    0x00000191 (main:14)           mov       eax,DWord Ptr [ebp-0x04]
    0x00000194 (main:14)           mov       DWord Ptr [ebp-0x08],eax

    ======================================================================

    1、从上述的汇编代码我们不难看出对于i=i+1; i++; ++i这三个指令的汇编
       指令无论是在VC下还是在SCO UNIX的cc下都是一样的(虽然这两个编译器
       对其汇编得到的指令不太一样,但是它们对这三条指令的汇编都是一样的,
       这里,我是关闭编译器优化的选项,也许现在的编译器自动对之优化了)

        在VC下都是:
     0040D6B5   mov         edx,dword ptr [ebp-4]
     0040D6B8   add         edx,1
     0040D6BB   mov         dword ptr [ebp-4],edx

        在cc下都是:
     0x0000017b (main:10)           inc       DWord Ptr [ebp-0x04]

    2、对于复合指令 j=i+1; j=i++; 却有所不同,
       在VC下:j=i+1 是三条指令,而 j=i++ 却有五条指令,这也很合理。
       在SCO下: j=i+1 和 j=i++ 都是三条指令。(j=i++指令数比VC少)

    3、对于i=i++,在VC下可以得到正确的结果 i=1;而在SCO下却是i=0; 这可以
       从其汇编看到。

       VC对i=i++的汇编是:

     0040D6A6   mov         eax,dword ptr [ebp-4] //取内存值i到eax
     0040D6A9   mov         dword ptr [ebp-4],eax //把eax值放到内存i中
     0040D6AC   mov         ecx,dword ptr [ebp-4] //取内存值i到ecx
     0040D6AF   add         ecx,1                 //寄存器ecx加1 
     0040D6B2   mov         dword ptr [ebp-4],ecx //把ecx值放到内存i中

       SCO对i=i++的汇编是:
           
     //取内存i到寄存器eax中
     0x0000016c (main:6)            mov       eax,DWord Ptr [ebp-0x04]

     //对内存i进行累加
     0x0000016f (main:6)            inc       DWord Ptr [ebp-0x04]
     
     //把寄存器eax的值放到内存i中
     0x00000172 (main:6)            mov       DWord Ptr [ebp-0x04],eax

        可见,之所以SCO得不到正确的结果的原因了。我已为其加上了注释,相信各位是看得懂的。

    【结论】:
        1、如果是单语句,无论是i=i+1; i++; ++i;其效率是完全一样的。
        2、之所以SCO下的i=i++得不到正确结果,是因为其编译器追求效率的结果。(Java亦如此)
        3、观察SCO下的汇编指令“inc DWord Ptr [ebp-0x04]”,难道可以直接操作内存吗?(拿不准)
        4、各个产商的编译器各有不同,所产生的语句的指令代码也有所不同,C++就更尤其如此啦。

    ======================================================================

    最后附上Java对i=i++的测试

    源程序:

     #1: class Test
     #2: {
     #3:  public static void main(String[] argv)
     #4:  {
     #5:  int i=0;
     #6:  i=i++;
     #7:  System.out.println("i="+i);
     #8: }
     #9: }


    用javac -g Test.java 把其编译成 Test.class。
    再用javap -c Test打出其虚拟机指令代码如下:

    D:\>javap -c Test

    Compiled from Test.java
    class Test extends java.lang.Object {
        Test();
        public static void main(java.lang.String[]);
    }

    Method Test()
       0 aload_0
       1 invokespecial #1 <Method java.lang.Object()>
       4 return

    Method void main(java.lang.String[])
       0 iconst_0
       1 istore_1
       2 iload_1
       3 iinc 1 1
       6 istore_1
       7 getstatic #2 <Field java.io.PrintStream out>
      10 new #3 <Class java.lang.StringBuffer>
      13 dup
      14 invokespecial #4 <Method java.lang.StringBuffer()>
      17 ldc #5 <String "i=">
      19 invokevirtual #6 <Method java.lang.StringBuffer append(java.lang.String)>
      22 iload_1
      23 invokevirtual #7 <Method java.lang.StringBuffer append(int)>
      26 invokevirtual #8 <Method java.lang.String toString()>
      29 invokevirtual #9 <Method void println(java.lang.String)>
      32 return

    可见其中的:
       1 istore_1
       2 iload_1
       3 iinc 1 1
       6 istore_1
    就是i=i++的虚拟机指令,想来一定和SCO的编译器有异曲同工之处。

    【备注】
        这段程序的结果是i=0,我是在 j2se 1.4.0 下进行的测试。
        虽然说,这是一个BUG,但是有多少人又会写i=i++这种无聊的语句呢?
        不过却可以了解一下编译器(解释器)的工作方式。

    ——
    (版权所有,如需转载,请注明作者和出处)

    发表于 @ 2003年04月04日 09:14:00|评论(loading...)|编辑

    新一篇: 编程修养(一) | 旧一篇: 用C写有面向对象特点的程序

    评论

    #fatalerror99 发表于2006-01-03 09:24:00  IP: 60.24.150.*
    无论 C 标准还是 C++ 标准,对于 i=i++ 这种语句的结果都是无定义的,换句话说,任何结果都不能认为是错误的,因为它是符合标准的。
    #a 发表于2006-11-21 20:08:00  IP: 221.239.61.*
    2、之所以SCO下的i=i++得不到正确结果,是因为其编译器追求效率的结果。(Java亦如此)
    ------------------------------------------------------------

    这句话,不敢苟同

    发表评论  


    登录
    Csdn Blog version 3.1a
    Copyright © 陈皓