StrcpyC语言的函数之一,来自 C语言标准函数库,定义于 string.h,它可以复制以 null 为结束字符的存储器区块到另一个存储器区块内。由于字符串在 C 语言不是首要的资料类型,而是以实现的方式来替代,在存储器内以连续的字节区块组成,strcpy 可以有效复制两个配置在存储器以指针回传的字符串(字符指针或是字符串指针)。

函数原型如下:[1]

#include<string.h>
char *strcpy(char *destination, const char *source);

传回值是 destination 字符数组或是配置在存储器的字符指针(或是字符串指针)。

使用方式与实现

例如

char *str1 = malloc(LARGE_NUMBER);
char *str2 = malloc(LARGE_NUMBER);

fgets(str1, LARGE_NUMBER, stdin);
strcpy(str2, str1); /* 這行程式碼類似 str2 "=" str1 */

前两行代码是先配置存储器,经由 malloc 函数把配置完成的存储器地址,传回给 str1str2。到了下一行代码,指向 str1 的存储器,会被用户输入的字符串填满。之后,复制 str1 字符串到 str2 的存储器区块内。虽然 str2 = str1 这个程序叙述可以出现类似的现象,但是它只能复制地址从 str1str2,让 str2 指向 str1 的存储器,实际上也无法真正做到复制字符串的动作。这就是 str1str2 两个指针都指向相同的存储器区块地址。这相当于所谓的 shallow copy(浅复制)英语Object copy,因为 str2 实际上没有真正从 str1 复制到字符串,所以这两个指针所指的其实都是同一个的字符串。

strcpy 函数利用循环动作逐次完成复制字符串中每一个字符。在GCC-4.8.0的testsuite中的实现如下:

extern void abort (void);
extern int inside_main;

__attribute__ ((__noinline__))
char *
strcpy (char *d, const char *s)
{
  char *r = d;
#if defined __OPTIMIZE__ && !defined __OPTIMIZE_SIZE__
  if (inside_main)
    abort ();
#endif
  while ((*d++ = *s++));
  return r;
}

缓存溢出

必须注意使用 strcpy 函数,因为如果来源字符串的长度太长,当复制到目的缓冲器时,它会改写到连接目的缓冲器后方的存储器,导致无法预期的结果。而且程序通常容易会出现区段错误(也就是常见的例外现象),但是熟练的骇客会利用缓存溢出来破解进入操作系统(详见电脑安全)。

Bounds checking variants

strncpy 这个常见的 bounded variant 它的实现方式与 strcpy 相类似,它只要复制指定的字节个数,而且只要它接近指定的最大长度时,就会在目的缓冲器加上结束字符来结束复制动作。只要指定的字节个数大于目的字符串的长度,它就会因为缓存溢出而受到影响;然而,程序会自动假定来源字符串是以 null 作为结束字符的字符串,当来源字符串的长度大于指定的长度时,它无法保证产生出来的结果是以 null 来作为结束字符的字符串,它也可能出现读取例外的现象。

strlcpy

OpenBSD 的研发人员 Todd C. MillerTheo de Raadt 两人设计 strlcpy 函数,通常视为是 strncpy 安全版本。对于一些操作系统而言,这个函数会出现被掌控的问题,但是它已经被 glibc 维修人员给特别地删除,所以在此建议使用 memcpy 函数来替代。[2]

strcpy_s

strcpy_s 函数是 strcpy 的安全版本,属于 ISO/IEC TR 24731 的标准, [3][4]某些 C 函数库支持这个函数,包含 Microsoft C Runtime Library(微软 C 语言执行时期函数库)。[5] 它与 strcpy 的不同在于,在它获取额外参数来决定目的缓冲器大小时,会因为发生溢出而出现错误,如此一来,就可以预防缓存溢出。由于 strcpy_s 对于 C 语言来说是新的函数,所以没有特别受到广泛支持。

反对Microsoft人士宣称,这个函数连同其他Microsoft在其Runtime Library号称对安全性所做的强化[6]皆为Microsoft试图把开发人员锁死在视窗平台上的手段之一。[7][8];虽然strcpy_s是属于ISO/IEC TR 24731的标准而非Windows独有的标准,且在本质上跟OpenBSD的strlcpy没有差别。

参考资料

  1. ^ 存档副本. [2007-06-11]. (原始内容存档于2007-06-10). 
  2. ^ libc-alpha mailing list页面存档备份,存于互联网档案馆), selected messages from 8 Aug 2000 thread: 53页面存档备份,存于互联网档案馆), 60页面存档备份,存于互联网档案馆), 61页面存档备份,存于互联网档案馆
  3. ^ ISO/IEC. ISO/IEC WDTR 24731 Specification for Secure C Library Functions. 国际标准化组织. 2004. 
  4. ^ Plakosh, Daniel. strcpy_s() and strcat_s(). Pearson Education, Inc. [2006-08-12]. (原始内容存档于2006-09-23). 
  5. ^ Microsoft. Security Enhancements in the CRT. MSDN. [2006-08-12]. 
  6. ^ Microsoft. Security Enhancements in the CRT. MSDN. [2008-09-16]. (原始内容存档于2008-09-13). 
  7. ^ Danny Kalev. They're at it again. InformIT. [2008-09-15]. (原始内容存档于2012-01-15). 
  8. ^ Security Enhanced CRT, Safer Than Standard Library?. [2008-09-15]. (原始内容存档于2008-09-19). 

外部链接