strcpy的实现方式是什么?

6

我有一个关于使用strcpy的问题。我知道ANSI C标准规定:源和目标不能重叠,否则行为是不可预测的。我给你展示一段代码,如果在Linux下使用旧的gnu C编译器编译,它会按照我的期望工作。

#include <string.h>
#include <stdio.h>

char S[80],*P;

int main() {
    strcpy(S,"abcdefghi\r\njklmnopqr\r\nstuvwxyz\r\n");
    for (P=S; P=strchr(P,'\r'); P++) strcpy(P,P+1);
    printf("%s\n",S);
    return 0;
}

这个序列从输入字符串中删除每一个\r(回车符)。从Kernigham和Ritchie的书中了解到,一个非常简单的strcpy实现如下:

while (*t++=*s++) ;

现在我使用gcc (Gentoo 4.5.4 p1.0, pie-0.4.7) 4.5.4编译我的程序,它输出如下:

abcdefghi
jklmnpqr          <-- missing 'o'
stuvwxxyz         <-- doubled 'x'

我猜想这个编译器(实际上是它的库)对于strcpy使用了非常复杂的序列,但我不明白原因。


1
呵呵,@jsalonen比我先编辑了。 - Earlz
你可以通过在你的系统中找到.asm文件来查看实现。 - elyashiv
1
它可能使用复制更大(多字节)块的优化。一种常见的技术是将指针转换为最长可用的整数单元(如long long *),并进行复制。这意味着复制会覆盖正在被复制的内容。 - Some programmer dude
奇怪的结果是 abcdefghi 然后 jklmnpqr 然后 stuvwxxyz。第二行缺少 o,第三行 x 重复了。 - Nelu Cozac
我使用gdb(gnu调试器)查看了S:每个'\r'都被删除,而S是“abcdefghi\njklmnpqr\nstuvwxxyz\n”。 - Nelu Cozac
显示剩余2条评论
2个回答

13

警告过你不要那样做。原因是逐字节复制实际上非常慢,需要循环扫描字符串。编译器可以轻松地优化这一点(例如:每次复制一个int大小的块,或使用某些特定于平台的并行处理)。

但是,如果字符串重叠,则这些优化会对您的数据进行不再有效的假设。结果,它们会给您未指定的结果。您的旧版GCC很可能根本没有执行任何此类优化。

由于strcpy()的文档说不要使用重叠的字符串,所以请不要这样做。


2

当然,了解你的实现正在做什么的最好方法是阅读其库的源代码。

如果源代码不可用,则下一个最佳选择可能是阅读编译器生成的汇编代码。

您还可以查看“严肃”的开源库的实现,并从中得出一些结论。

一个想法可能是该库在复制数据时使用了比单个字符更大的块,这会在违反设计假设时导致错误。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接