当前位置:C++技术网 > 资讯 > 函数内部分析:6 memcpy和memcpy_s函数内部执行原理分析

函数内部分析:6 memcpy和memcpy_s函数内部执行原理分析

更新时间:2015-06-25 21:14:33浏览次数:1+次

    mencpy和memcpy_s都是在头文件memcpy.h中声明,使用前需要包含这个头文件。
memcpy函数原型
void * memcpy (void * dst,const void * src,size_t count);
    此函数用于对内存进行复制,按照字节复制。第一个参数是目标内存地址,第二个参数是源内存地址,第三个参数是字节数。返回目标地址的指针。
    返回指针和参数中的指针都是void*类型的,因为是对内存字节进行复制,因此不必不必指定类型,复制完后,再将目标内存地址转换成你需要的类型即可。
    memcpy函数中,直接对内存进行复制,按照内存地址,复制指定的字节数。这个函数没有任何保证,所以使用一定要正确,否则会出现内存操作违规。如果传入的参数中的指针任何一个为空,那么执行此函数会导致内存操作失败,直接导致程序崩溃。这就是今天我调试程序发现程序中的一个问题。这种问题一般很难发现。所以使用此函数前,一定要保证传入的参数的指针是有效的(不仅不为空,且指向的内存是有效的)。这个函数内部就这么简单,也就可能带来操作不当引起程序崩溃。

memcpy_s函数原型
errno_t memcpy_s(void * dst,size_t sizeInBytes,const void * src,size_t count);
    第一个参数为目标内存地址,第二个参数为目标内存缓冲大小,第三个参数为源内存地址,第四个为源内存缓冲的大小。返回值是一个错误码。
    为什么这个返回值是错误码呢?因为这个版本中加入了基本的错误检测。如果源缓冲大小为0,即count为0,函数返回0,什么也不做。此函数没有对目标指针为NULL的情况,不做检查,所以你自己要注意检查。如果指针有值,但是是无效值,函数也没办法检查是否是有效内存,只是会搜集这些信息,在程序崩溃时提供调试需要的信息。
    然后检查源地址是否为空或count是否大于sizeInBytes,两个条件有一个满足,函数中先将目标内存以sizeInBytes指定的大小调用memset函数清0.这里可以看出,如果sizeInBytes传入的大小超出目标缓冲区的大小,也是会带来隐患的,一旦清除了其他进程的或者其他线程的内存,都是带来问题,也很可能导致内存操作违规。所以,第二个参数的大小不能超过目标缓冲的大小,以字节为单位。然后程序搜集错误信息,最后返回错误码,并不会执行内存复制的过程。前面说的这是两个条件任意一个进入都会导致失败,所以在搜集信息时,程序会对进入的条件进行判断,然后进行搜集。
    只有这些检查通过,才会调用memcpy函数执行内存复制过程。而第二个参数只是内部用来检测和清除目标内存而使用的。
    函数memcpy_s执行完毕后返回0,所以检查返回值是否为0不能判断是否成功。但是返回值为非零那就是失败了。
    虽然说加上_s版本的函数是安全版本,但是也是会出现问题的,使用时也要注意,即使有时候不崩溃,但是一旦改写了其他的线程的内存,必然导致程序运行不正常,因为线程的数据被破坏,至少逻辑会出错。
    不过,_s版本函数提供了一定的检测,并且在release版本也可以报错,可以进一步调试问题,而memcpy则在release版本中不会报错。