strcpy 是如何实现的?

Posted

技术标签:

【中文标题】strcpy 是如何实现的?【英文标题】:How is strcpy implemented? 【发布时间】:2012-10-07 18:33:20 【问题描述】:

我有一个关于使用 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 使用了一个非常复杂的序列,我不明白其中的原因。

【问题讨论】:

嘿,@jsalonen 比我更容易编辑 您可以通过在系统中找到 .asm 文件来查看实现。 它可能使用了复制更大(多字节)块的优化。一种常见的技术是将指针转换为最长的可用整数单元(如long long *)并复制它。这意味着副本会覆盖正在复制的内容。 奇怪的结果是 abcdefghi 然后 jklmnpqr 然后 stuvwxxyz 。第二行 o 缺失,第三行 x 加倍。 我使用 gdb(gnu 调试器)查看了 S:每个 '\r' 都被删除并且 S 是 "abcdefghi\njklmnpqr\nstuvwxxyz\n" 【参考方案1】:

您被警告不要这样做。原因是逐字节复制实际上非常慢,并且需要大量循环才能通过字符串。编译器可以很容易地对此进行优化(例如,通过一次复制一个int 大小的块,或者使用一些特定于平台的并行化。)

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

由于strcpy() 的文档说不要使用重叠字符串,不要

【讨论】:

【参考方案2】:

弄清楚你的实现在做什么的最好方法当然是阅读它的库的源代码。

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

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

一个想法可能是库一次复制比字符更大的数据块,当您违反设计假设时会中断。

【讨论】:

以上是关于strcpy 是如何实现的?的主要内容,如果未能解决你的问题,请参考以下文章

strcpy函数的实现

实现Strcpy函数 - 通过函数发现 “程序之美” | 不断优化优化再优化~

strcpy函数体现出的编程细节

memcpymemmovememset及strcpy函数实现和理解

一个关键的函数——strcpy的实现

手写strcpy和memcpy代码实现