Chinaunix首页 | 论坛 | 博客
  • 博客访问: 49531
  • 博文数量: 5
  • 博客积分: 313
  • 博客等级: 入伍新兵
  • 技术积分: 85
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-14 14:36
文章分类

全部博文(5)

文章存档

2012年(3)

2011年(2)

分类: C/C++

2011-11-08 09:11:16

源代码直接Copy 见谅

据说这个是GNU的写法(my_strcpy2)
char * 
my_strcpy2 (dest, src)
     char *dest;
     const char *src;
{
  register char c;
  char * s = (char *)src;
  const int off = dest - s - 1;
  do{
      c = *s++;
      s[off] = c;
    }while (c != '\0');
  return dest;
}
另外一种写法来自GFree_Wind(my_strcpy1)

char* my_strcpy1(char *dest, const char *src)
{
    char *d = dest;
    register char c;
    do{
        c = *src++;
        *d++ = c;
    } while ('\0' != c);
    return dest;
}

根据 CFree_Wind 大牛的说法 (本人小菜)1的效率要高于2 详情如下

既然大牛说大家都是学习那我使用VS2008 捣鼓了一番
这个是第一种反汇编出来的 为了不影响统计排除了空行和不考虑编译器的优化
  1. char* my_strcpy1(char *dest, const char *src)
  2. {
  3. 004113D0 push ebp
  4. 004113D1 mov ebp,esp
  5. 004113D3 sub esp,0D8h
  6. 004113D9 push ebx
  7. 004113DA push esi
  8. 004113DB push edi
  9. 004113DC lea edi,[ebp-0D8h]
  10. 004113E2 mov ecx,36h
  11. 004113E7 mov eax,0CCCCCCCCh
  12. 004113EC rep stos dword ptr es:[edi]
  13.     char *d = dest;
  14. 004113EE mov eax,dword ptr [dest]
  15. 004113F1 mov dword ptr [d],eax
  16.     register char c;
  17.     do {
  18.         c = *src++;
  19. 004113F4 mov eax,dword ptr [src]
  20. 004113F7 mov cl,byte ptr [eax]
  21. 004113F9 mov byte ptr [c],cl
  22. 004113FC mov edx,dword ptr [src]
  23. 004113FF add edx,1
  24. 00411402 mov dword ptr [src],edx
  25.         *d++ = c;
  26. 00411405 mov eax,dword ptr [d]
  27. 00411408 mov cl,byte ptr [c]
  28. 0041140B mov byte ptr [eax],cl
  29. 0041140D mov edx,dword ptr [d]
  30. 00411410 add edx,1
  31. 00411413 mov dword ptr [d],edx
  32.     } while ('\0' != c);
  33. 00411416 movsx eax,byte ptr [c]
  34. 0041141A test eax,eax
  35. 0041141C jne my_strcpy1+24h (4113F4h)
  36.     return dest;
  37. 0041141E mov eax,dword ptr [dest]
  38. };
  39. 00411421 pop edi
  40. 00411422 pop esi
  41. 00411423 pop ebx
  42. 00411424 mov esp,ebp
  43. 00411426 pop ebp
  44. 00411427 ret
这个是2种写法的汇编
  1. char * my_strcpy2 (char *dest, const char *src)
  2. {
  3. 00411440 push ebp
  4. 00411441 mov ebp,esp
  5. 00411443 sub esp,0E4h
  6. 00411449 push ebx
  7. 0041144A push esi
  8. 0041144B push edi
  9. 0041144C lea edi,[ebp-0E4h]
  10. 00411452 mov ecx,39h
  11. 00411457 mov eax,0CCCCCCCCh
  12. 0041145C rep stos dword ptr es:[edi]
  13.     register char c;
  14.     char * s = (char *)src;
  15. 0041145E mov eax,dword ptr [src]
  16. 00411461 mov dword ptr [s],eax
  17.     const int off = dest - s - 1;
  18. 00411464 mov eax,dword ptr [dest]
  19. 00411467 sub eax,dword ptr [s]
  20. 0041146A sub eax,1
  21. 0041146D mov dword ptr [off],eax
  22.     do{
  23.         c = *s++;
  24. 00411470 mov eax,dword ptr [s]
  25. 00411473 mov cl,byte ptr [eax]
  26. 00411475 mov byte ptr [c],cl
  27. 00411478 mov edx,dword ptr [s]
  28. 0041147B add edx,1
  29. 0041147E mov dword ptr [s],edx
  30.         s[off] = c;
  31. 00411481 mov eax,dword ptr [s]
  32. 00411484 add eax,dword ptr [off]
  33. 00411487 mov cl,byte ptr [c]
  34. 0041148A mov byte ptr [eax],cl
  35.     }
  36.     while (c != '\0');
  37. 0041148C movsx eax,byte ptr [c]
  38. 00411490 test eax,eax
  39. 00411492 jne my_strcpy2+30h (411470h)
  40.     return dest;
  41. 00411494 mov eax,dword ptr [dest]
  42. };
  43. 00411497 pop edi
  44. 00411498 pop esi
  45. 00411499 pop ebx
  46. 0041149A mov esp,ebp
  47. 0041149C pop ebp
  48. 0041149D ret
分析:
第一种一共44行代码 第二种 48行代码 如果汇编的代码条数作为算法的效率那么真的是第一种效率高吗?

两段代码最主要的差异在这个位置
  1. *d++ = c;
  2. 00411405 mov eax,dword ptr [d]
  3. 00411408 mov cl,byte ptr [c]
  4. 0041140B mov byte ptr [eax],cl
  5. 0041140D mov edx,dword ptr [d]
  6. 00411410 add edx,1
  7. 00411413 mov dword ptr [d],edx
  1. s[off] = c;
  2. 00411481 mov eax,dword ptr [s]
  3. 00411484 add eax,dword ptr [off]
  4. 00411487 mov cl,byte ptr [c]
  5. 0041148A mov byte ptr [eax],cl

GNU 在循环里面 少用了 2条汇编指令
不是我崇洋媚外 确实这个地方相当精妙
使用堆栈平行的内存空间来节省 CPU所执行的指令数这个是非常精妙的

虽然我没有进行进一步的实际测试 但是 CFree_Wind 大牛我个人不同意您的说法 
如果循环仅执行一次那么您的效率要高但是如果忽略循环外面的代码影响那么GNU的算法效率是您的

10/12=80%左右
 可以断然 如果实际使用中 GNU的算法效率比第一种写法提高了 10%-20%


 
阅读(4416) | 评论(14) | 转发(0) |
0

上一篇:没有了

下一篇:【非技術】strcpy两种写法的看法

给主人留下些什么吧!~~

GFree_Wind2011-11-10 15:35:55

aindk: 我换了一种 时间计算 方法 用系统 的 windows api 来获取时间
发现 最快的是 1一种 GNU比第一种 某些时候差0.000001 单位具体也不太清楚

最后一种 比较慢 相.....
如果是windows,陈皓写过一个如何精确计时。

aindk2011-11-10 14:55:53

GFree_Wind: 没错,c语言的语句行数少并不一定会效率高。不过你误会了我的意思。
这个写法,我只是为了免去文中的my_strcpy1的register的复制,也就是少了一次拷贝,且考虑*.....
我换了一种 时间计算 方法 用系统 的 windows api 来获取时间
发现 最快的是 1一种 GNU比第一种 某些时候差0.000001 单位具体也不太清楚

最后一种 比较慢 相差 比较大 0.000002~0.000004

我个人分析 产生原因 如下
1、无法确保精确计时 因为是4核心CPU
2、VC 是用的 托管堆的形式 不是操作的实际内存 估计CPU 花费了大量的时间片在计算内存的实际地址(猜测 对于VC 托管内存不是很精通)

aindk2011-11-09 23:01:07

GFree_Wind: 你做了多少次比较?
方便使用下面这个strcpy试一下吗?

char* my_strcpy1(char *dst, const char *src)
{
    char *d = dst;

    while((*dst++ = *src++) !.....


这种简洁的 写法 其实质上 只能够忽悠 一下 初学者  想想 CPU 是不认人 的 他 仅认指令条数

给多少条指令 做多少活

简洁的写法 在 编译过后 都被拆成一条一条 的

看代码的效率 不是 看 源代码的 长度 而是看 编译后 产生

GFree_Wind2011-11-09 22:22:27

aindk:

不好意思下班了........
没关系。明天等你的结果。这个my_strcpy1是我最早的实现。

aindk2011-11-09 22:05:59

GFree_Wind: 你做了多少次比较?
方便使用下面这个strcpy试一下吗?

char* my_strcpy1(char *dst, const char *src)
{
    char *d = dst;

    while((*dst++ = *src++) !.....


不好意思下班了...