水儿 大约1小时前 无聊 的说 生命不熄,灌水不止.......   timi 大约3小时前 平静 的说 降温了   sunnytoy 大约12小时前 平静 的说 无奈呀   ㄣ苐②噤區℡ 大约14小时前 思念 的说 情何以堪啊~   鲍豪斯 大约16小时前 平静 的说 提醒您注意保暖…   jacky200247 大约16小时前 平静 的说 对不起,我不想再这样等下去了。   无耻之兔 大约21小时前 生气 的说 机电又分钱了   丰之痛 12月3日 高兴 的说 今天又想去打篮球了!!!!   丰之痛 12月2日 郁闷 的说 机电那伙人太火了..........   看海的日子 12月2日 平静 的说 输入要叽歪的内容_   [查看全部 456 条唧唧歪歪...]


打印

位运算交换和变量交换的汇编比较(讨论)

位运算交换和变量交换的汇编比较(讨论)

呵呵,一年多没有做过关于C的东西了,今天趁着兴起,多做点点,明天,继续c sharp..8-)
下面是传说中的不用变量交换两个值的例子,看看到底何方神圣
$ gcc -g test.c -o test

YETIboy@ ~
$ gdb test
GNU gdb 2003-09-20-cvs (cygwin-special)
Copyright 2003 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License,
welcome to change it and/or distribute copies of it under certai
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" f
This GDB was configured as "i686-pc-cygwin"...
(gdb) l
1     #include <stdlib.h>
2     void func(int *m, int *n) {
3        int temp;
4        temp = *m;
5        *m = *n;
6        *n = temp;
7     }
8     main() {
9          int a = 31, b = 123;
10         printf("Before exchanging:\ta = %d,b = %d \n", a,
(gdb)
11         a = a ^ b;
12         b = b ^ a;
13         a = a ^ b;
14         printf("Exchange&#39;s done:\ta = %d,b = %d",a,b);
15         func(&a,&b);
16         printf("\nExchanged Again!\ta = %d,b = %d",a,b);
17    }
(gdb) r
Starting program: /home/YETIboy/test.exe
Before exchanging:    a = 31,b = 123
Exchange&#39;s done:      a = 123,b = 31
Exchanged Again!      a = 31,b = 123
Program exited with code 040.
※※※以上是运行结果的检验※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※
(gdb) disass main
Dump of assembler code for function main:
0x00401110 <main+0>:   push  %ebp
0x00401111 <main+1>:   mov   %esp,%ebp
0x00401113 <main+3>:   sub   $0x18,%esp 在这里声请局部变量空间!!!!
0x00401116 <main+6>:   and   $0xfffffff0,%esp
0x00401119 <main+9>:   mov   $0x0,%eax
0x0040111e <main+14>:  mov   %eax,0xfffffff4(%ebp)
0x00401121 <main+17>:  mov   0xfffffff4(%ebp),%eax
0x00401124 <main+20>:  call  0x4014f0 <_alloca>
0x00401129 <main+25>:  call  0x401580 <__main>
******进入main函数块******************************************
0x0040112e <main+30>:  movl  $0x1f,0xfffffffc(%ebp)   a = 31;
0x00401135 <main+37>:  movl  $0x7b,0xfffffff8(%ebp)  b = 123;
0x0040113c <main+44>:  mov   0xfffffff8(%ebp),%eax   b的值放到eax中
0x0040113f <main+47>:  mov   %eax,0x8(%esp,1)      借助于eax把b的值传给printf参数表
0x00401143 <main+51>:  mov   0xfffffffc(%ebp),%eax   把a的值放到eax中
0x00401146 <main+54>:  mov   %eax,0x4(%esp,1) 借助于eax把a的值传给printf参数表!
0x0040114a <main+58>:  movl  $0x401090,(%esp,1)
0x00401151 <main+65>:  call  0x401590 <printf>  呼叫printf,c libarary runtime,传递a,b的值给printf
0x00401156 <main+70>:  mov   0xfffffff8(%ebp),%edx   把b的值传给edx
0x00401159 <main+73>:  lea   0xfffffffc(%ebp),%eax     把a的地址!!传给eax
0x0040115c <main+76>:  xor   %edx,(%eax)              a = a^b
0x0040115e <main+78>:  mov   0xfffffffc(%ebp),%edx    把a的值放到edx中
0x00401161 <main+81>:  lea   0xfffffff8(%ebp),%eax    得到b的地址放到eax中
0x00401164 <main+84>:  xor   %edx,(%eax)             b = b^a
---Type <return> to continue, or q <return> to quit---
0x00401166 <main+86>:  mov   0xfffffff8(%ebp),%edx   
0x00401169 <main+89>:  lea   0xfffffffc(%ebp),%eax
0x0040116c <main+92>:  xor   %edx,(%eax)              a = a^b
*********位运算共用9句指令完成交换****************************************
0x0040116e <main+94>:  mov   0xfffffff8(%ebp),%eax
0x00401171 <main+97>:  mov   %eax,0x8(%esp,1)
0x00401175 <main+101>:  mov   0xfffffffc(%ebp),%eax
0x00401178 <main+104>:  mov   %eax,0x4(%esp,1)
0x0040117c <main+108>:  movl  $0x4010d0,(%esp,1)
0x00401183 <main+115>:  call  0x401590 <printf> 再次接受a,b的值,调用printf
0x00401188 <main+120>:  lea   0xfffffff8(%ebp),%eax
0x0040118b <main+123>:  mov   %eax,0x4(%esp,1)
0x0040118f <main+127>:  lea   0xfffffffc(%ebp),%eax
0x00401192 <main+130>:  mov   %eax,(%esp,1)
0x00401195 <main+133>:  call  0x401050 <func>  再次把a,b的值放入参数表,调用func
0x0040119a <main+138>:  mov   0xfffffff8(%ebp),%eax
0x0040119d <main+141>:  mov   %eax,0x8(%esp,1)
0x004011a1 <main+145>:  mov   0xfffffffc(%ebp),%eax
0x004011a4 <main+148>:  mov   %eax,0x4(%esp,1)
0x004011a8 <main+152>:  movl  $0x4010f0,(%esp,1)
0x004011af <main+159>:  call  0x401590 <printf> 最后一次调用printf,同样接受参数a,b
0x004011b4 <main+164>:  leave  释放堆栈帧
0x004011b5 <main+165>:  ret    返回上级函数(就是调用main()的函数!它们是操作系统装载exe和退出程序时作的清理工作,类似于c++的构造函数和析构函数的功能)
※※※※※※※※※※※※※※※※※※※main()结束※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※
End of assembler dump.
(gdb) disass func
※※※※※※※※※※※※※※※查看func的代码※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※
Dump of assembler code for function func:
0x00401050 <func+0>:   push  %ebp
0x00401051 <func+1>:   mov   %esp,%ebp 建立堆栈帧,用来函数返回
0x00401053 <func+3>:   sub   $0x4,%esp  声请一个变量地址(没有赋值!!)
0x00401056 <func+6>:   mov   0x8(%ebp),%eax 把a的地址放到eax中
0x00401059 <func+9>:   mov   (%eax),%eax    取m的值到eax中
0x0040105b <func+11>:  mov   %eax,0xfffffffc(%ebp) temp = *m
0x0040105e <func+14>:  mov   0x8(%ebp),%edx 把a的地址放到edx中
0x00401061 <func+17>:  mov   0xc(%ebp),%eax 把b的地址放到eax中
0x00401064 <func+20>:  mov   (%eax),%eax    把b的值放到eax中
0x00401066 <func+22>:  mov   %eax,(%edx)    *m = *n
0x00401068 <func+24>:  mov   0xc(%ebp),%edx 把b的地址放到edx中
0x0040106b <func+27>:  mov   0xfffffffc(%ebp),%eax temp的值放到eax中
0x0040106e <func+30>:  mov   %eax,(%edx) *n = temp;
***************共用10句完成交换,并且多了个变量空间************************
0x00401070 <func+32>:  leave
0x00401071 <func+33>:  ret
End of assembler dump.
(gdb)
光从语句来判定,位运算胜利:)
下面我来试试谁到底更快

TOP

可能有人注意到了 [s:5]
不好意思,突然发现我比较得很不公平,我比较的时候,居然一个是函数调用,一个不是!
重写了一下
$ gcc -g test.c -o test -pg

YETIboy@ ~
$ ./test
the no. of iteration  is :100000000
YETIboy@ ~
$ gdb test
GNU gdb 2003-09-20-cvs (cygwin-special)
Copyright 2003 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public Lice
welcome to change it and/or distribute copies of it under ce
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warrant
This GDB was configured as "i686-pc-cygwin"...
(gdb) l 1
1     #include <stdlib.h>
2     void func(int *m, int *n) {
3        int temp;
4        temp = *m;
5        *m = *n;
6        *n = temp;
7     }
8     void bits(int *a, int *b) {
9        *a = *a ^ *b;
10        *b = *b ^ *a;
(gdb)
11        *a = *a ^ *b;
12    }
13
14    main() {
15         int a = 31, b = 123;
16         int i,k = 0;
17         for (i = 0; i < 100000000; i++) {
18            func(&a,&b);
19            bits(&a,&b);
20            k ++;
(gdb)
21          }
22         printf("the no. of iteration  is :%d",k);
23    }
(gdb) q

YETIboy@~
$ gprof test.exe gmon.out -p
Flat profile:
***************************************************************
Each sample counts as 0.01 seconds.
  %  cumulative  self          self    total
time  seconds  seconds   calls  ns/call  ns/call  name
46.50    1.13    1.13 100000000   11.30   11.30  bits
30.45    1.87    0.74                    main
23.05    2.43    0.56 100000000    5.60    5.60  func  
****************************************************************
voliaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!
眼见为实,终于出来了,和我开始想的一样,省下变量的位运算是要付出代价的!,那就是时间!!呵呵。。。
再看一下,多运行点时间看看

TOP

$ gcc -g test.c -o test -pg

YETIboy@7 ~
$ ./test
the no. of iteration  is :1000000000
YETIboy@ ~
$ gprof test.exe gmon.out -p
Flat profile:

Each sample counts as 0.01 seconds.
  %  cumulative  self          self    total
time  seconds  seconds   calls  ns/call  ns/call  name
46.00    13.53   13.53 1000000000   13.53   13.53  bits
28.22    21.83    8.30                    main
25.77    29.41    7.58 1000000000    7.58    7.58  func

呵呵,还是一样,可能有人想看看汇编了,是不是代码也要长点?对了
(gdb) disass func
Dump of assembler code for function func:
0x00401090 <func+0>:   push  %ebp
0x00401091 <func+1>:   mov   %esp,%ebp
0x00401093 <func+3>:   sub   $0x4,%esp
0x00401096 <func+6>:   mov   $0x403000,%edx
0x0040109b <func+11>:  call  0x4018f0 <mcount>
0x004010a0 <func+16>:  mov   0x8(%ebp),%eax
0x004010a3 <func+19>:  mov   (%eax),%eax
0x004010a5 <func+21>:  mov   %eax,0xfffffffc(%ebp)
0x004010a8 <func+24>:  mov   0x8(%ebp),%edx
0x004010ab <func+27>:  mov   0xc(%ebp),%eax
0x004010ae <func+30>:  mov   (%eax),%eax
0x004010b0 <func+32>:  mov   %eax,(%edx)
0x004010b2 <func+34>:  mov   0xc(%ebp),%edx
0x004010b5 <func+37>:  mov   0xfffffffc(%ebp),%eax
0x004010b8 <func+40>:  mov   %eax,(%edx)
0x004010ba <func+42>:  leave
0x004010bb <func+43>:  ret
End of assembler dump.
(gdb) disass bits
******下面位bits()***********************************
Dump of assembler code for function bits:
0x004010bc <bits+0>:   push  %ebp
0x004010bd <bits+1>:   mov   %esp,%ebp
0x004010bf <bits+3>:   mov   $0x403004,%edx
0x004010c4 <bits+8>:   call  0x4018f0 <mcount>
0x004010c9 <bits+13>:  mov   0x8(%ebp),%ecx
0x004010cc <bits+16>:  mov   0x8(%ebp),%edx
0x004010cf <bits+19>:  mov   0xc(%ebp),%eax
0x004010d2 <bits+22>:  mov   (%eax),%eax
0x004010d4 <bits+24>:  xor   (%edx),%eax
0x004010d6 <bits+26>:  mov   %eax,(%ecx)
0x004010d8 <bits+28>:  mov   0xc(%ebp),%ecx
0x004010db <bits+31>:  mov   0xc(%ebp),%edx
0x004010de <bits+34>:  mov   0x8(%ebp),%eax
0x004010e1 <bits+37>:  mov   (%eax),%eax
0x004010e3 <bits+39>:  xor   (%edx),%eax
0x004010e5 <bits+41>:  mov   %eax,(%ecx)
0x004010e7 <bits+43>:  mov   0x8(%ebp),%ecx
0x004010ea <bits+46>:  mov   0x8(%ebp),%edx
0x004010ed <bits+49>:  mov   0xc(%ebp),%eax
0x004010f0 <bits+52>:  mov   (%eax),%eax
0x004010f2 <bits+54>:  xor   (%edx),%eax
0x004010f4 <bits+56>:  mov   %eax,(%ecx)
0x004010f6 <bits+58>:  pop   %ebp
---Type <return> to continue, or q <return> to quit---
0x004010f7 <bits+59>:  ret
End of assembler dump.
(gdb)
那个长点,数一下就知道了:)
不知不觉,就将近3个小时了,马上凌晨3点了,明天继续c sharp了,什么时候研究下c++的汇编,好像太难,感觉,呵呵
如果有人想多了解下汇编(注意这是AT&T汇编,不是intel的,不过出不多),加深理解的话,看这个地址,正是它激发了我的兴趣:)http://www.712100.com/bbs/read-htm-tid-6689783.html
如果想多看看

TOP

哥们有AT&T汇编的资料 吗,网上好像很少 ,有的话能不能给我看看 !!! [s:827]  [s:827]  [s:827]  [s:827]  [s:827]  [s:827]  [s:827]  [s:827]

TOP

引用:
引用第3楼madaha2006-11-04 09:05发表的:
哥们有AT&T汇编的资料 吗,网上好像很少 ,有的话能不能给我看看 !!! [s:827]  [s:827]  [s:827]  [s:827]  [s:827]  [s:827]  [s:827]  [s:827]
http://bobo463.bokee.com/2425150.html
http://www.linuxsky.net/html/200405/350.html
我帮你搜了一下,感觉贝尔实验室的汇编语法要人性化点,呵呵

TOP

先 谢谢了!

TOP