读书人

strcpy实现的有关问题!

发布时间: 2012-10-06 17:34:01 作者: rapoo

strcpy实现的问题!!
最近看到林瑞的那个高质量编程指南,对于他写的strcpy的实现,我有几点不明白

C/C++ code
static char * strcpy(char *dest, const char *src){  assert(dest != NULL && src != NULL);  char *ret = dest;  while ((*dest++ = *src++) != '\0')        ;  return ret;}

1.首先
C/C++ code
while((*dest++ = *src++) != '\0');

这样写,执行结束以后,指针不都是指向字符串以外了吗,这样可以吗,安全吗?
2.其次
C/C++ code
while((*dest = *src))    dest++,src++;

他说会有10%的性能损耗,希望懂汇编的朋友解释一下(偶看不懂汇编(0^^0))
(我看了bsd的libc中关于strcpy的源码,人家貌似用的就是林博士认为性能损失的用法啊))
3.最后
C/C++ code
tatic char * strcpy(char *dest, const char *src){    assert(dest != NULL && src != NULL);  char *s = (char *)src;  int delt = dest - src;  while ((s[delt] = *s++) != '\0')        ;  return dest;}

他这个实现看不大明白啊
C/C++ code
int delt = dest - src;while ((s[delt] = *s++) != '\0');

这个s[delt]到底什么意思啊??
希望大大们不吝赐教啊,在下感激不尽!!

[解决办法]
1 效率和安全是两码事,追求越高效率的代码越不安全
这里不检测指针所指的是不是在允许范围内,就是为了提高效率
不安全的是dest指针,可能造成缓冲区溢出问题,src指针只用来读内存,很安全

2 我不知道10%是怎么计算出来的,在我理解中这应该和编译器的优化能力有关,也许作者是自己实际测试并统计出来的结果吧

3 两个指针分别++也许会降低效率,反正是逐一复制,直接记录第一个指针和两个指针的差,然后每次第一个指针++,用第一个指针加上差值就是第二个指针了。至于效率不好说,我觉得还是要看编译器的优化水平
a[b] == *(a+b),这是语言标准规定的[]操作符意义。既然belt等于dest - src,那么src + belt就等于dest
[解决办法]
可以通过效率测试 测得损失10% 具体的估计博士不想给你说
至于汇编得出的结果如下

; Function compile flags: /Odtp
_ret$ = -4; size = 4
_dest$ = 8; size = 4
_src$ = 12; size = 4
_strcpyPROC
; Line 12
pushebp
movebp, esp
pushecx
; Line 13
moveax, DWORD PTR _dest$[ebp]
movDWORD PTR _ret$[ebp], eax
$LN2@strcpy:
; Line 14
movecx, DWORD PTR _dest$[ebp]
movedx, DWORD PTR _src$[ebp]
moval, BYTE PTR [edx]
movBYTE PTR [ecx], al
movecx, DWORD PTR _dest$[ebp]
movsxedx, BYTE PTR [ecx]
moveax, DWORD PTR _dest$[ebp]
addeax, 1
movDWORD PTR _dest$[ebp], eax
movecx, DWORD PTR _src$[ebp]
addecx, 1
movDWORD PTR _src$[ebp], ecx
testedx, edx
jeSHORT $LN1@strcpy
jmpSHORT $LN2@strcpy
$LN1@strcpy:
; Line 15
moveax, DWORD PTR _ret$[ebp]
; Line 16
movesp, ebp
popebp
ret0
_strcpyENDP
; Function compile flags: /Odtp
_ret$ = -4; size = 4
_dest$ = 8; size = 4
_src$ = 12; size = 4
?strcpy1@@YAPADPADPBD@Z PROC; strcpy1
; Line 18
pushebp
movebp, esp
pushecx
; Line 19
moveax, DWORD PTR _dest$[ebp]
movDWORD PTR _ret$[ebp], eax
$LN2@strcpy1:
; Line 20
movecx, DWORD PTR _dest$[ebp]
movedx, DWORD PTR _src$[ebp]
moval, BYTE PTR [edx]
movBYTE PTR [ecx], al
movecx, DWORD PTR _dest$[ebp]
movsxedx, BYTE PTR [ecx]
testedx, edx
jeSHORT $LN1@strcpy1
; Line 21
moveax, DWORD PTR _dest$[ebp]
addeax, 1
movDWORD PTR _dest$[ebp], eax
movecx, DWORD PTR _src$[ebp]
addecx, 1
movDWORD PTR _src$[ebp], ecx
jmpSHORT $LN2@strcpy1
$LN1@strcpy1:
; Line 22
moveax, DWORD PTR _ret$[ebp]
; Line 23


movesp, ebp
popebp
ret0
?strcpy1@@YAPADPADPBD@Z ENDP; strcpy1
_TEXTENDS
END

代码相同 唯一不同的是结构不同
每次while循环都要判断一次是否满足条件

jeSHORT $LN1@strcpy
jeSHORT $LN1@strcpy1
如果不满足条件就返回
返回时 第一个只需要esp指针向下移动一行 即可到达指定内存地址
而第二个需要移动7行
大概这10%就体现在这里吧 但是如果while循环时间趋向于无限长 相对的这所谓的%10也许会下降到0%

但实际上也可能跟指令周期有关 一般相对集中的调用一种指令 比分散开来调用更有效率 这和实际中的流水线原理是相同的 至于硬件方面的要涉及到interCPU的内部结构 这个不了解 无法解答
[解决办法]
1. 本论坛有帖子“如何理解指针指向数组最后元素的下一个地址空间是合法的”

2。 理论上讲,分支会导致流水线中被插入气泡,至于 10%,应该是某种环境下测试的,不一定适用于一切环境

3。个人认为是个错误

读书人网 >C语言

热点推荐