memcpy可能产生的问题


 

一、https://blog.csdn.net/qq51931373/article/details/50788059

memcpy()、memset()、memcmp()等这些内存操作函数经常会帮我们完成一些数据复制、赋值等操作。因为在C语言中,无论是内置类型,还是自定义的结构类型(struct),其内存模型对于我们来说都是可知的、透明的。所以,我们可以对该对象的底层字节序列一一进行操作,简单而有效。代码片段如下所示:


struct STUDENT  
{  
     char _name[32];  
     int _age;  
     bool _gender;  
};  
 
STUDENT a = {"Li Lei", 20, true};  
STUDENT b = {"Han MeiMei", 19, false};  
 
int len = sizeof(STUDENT);  
STUDENT c;  
memset(&c, 0, len);  
memcpy(&c, &a, len);  
 
char *data = (char*)malloc(sizeof(char)*len);  
memcpy(data, &b, len);

在C++中,我们把传统C风格的数据类型叫做POD(Plain Old Data)对象,即一种古老的纯数据。在C的世界里根本没有POD这一概念,因为C的所有对象都是POD。一般来说,POD对象应该满足如下特性:其二进制内容是可以随意复制的,无论在什么地方,只要其二进制内容存在,我们就能准确无误地还原出POD对象。正是由于这个原因,对于任何POD对象,我们都可以放心大胆地使用memset()、memcpy()、memcmp()等函数对对象的内存数据进行操作。

然而在C++中,每个人都要十二分的注意了。因为C++的对象可能并不是一个POD,所以我们无法像在C中那样获得该对象直观简洁的内存模型。对于POD对象,我们可以通过对象的基地址和数据成员的偏移量获得数据成员的地址。但是C++标准并未对非POD对象的内存布局做任何定义,对于不同的编译器,其对象布局是不同的。而在C语言中,对象布局仅仅会受到底层硬件系统差异的影响。

针对非POD对象,其序列化会遇到一定的障碍:由于对象的不同部分可能存在于不同的地方,因而无法直接复制,只能通过手工加入序列化操作代码来处理对象数据,很麻烦。但是针对POD对象,这一切将变得不再困难:从基地址开始,直接按对象的大小复制数据,或传输,或存储,随意处理。

为什么C++中的对象有可能不是一个POD呢?这还要从C++的重要特征之一—动多态说起。动多态的一个基本支撑技术就是虚函数。在使用虚函数时,类的每一次继承都会产生一个虚函数表(vtable),其中存放的是指向虚函数的指针。这些虚函数表必须存放在对象体中,也就是和对象的数据存放在一起。因而,对象数据在内存里并不是以连续的方式存放的,而是被分割成了不同的部分,甚至“身首异处”。既然对象数据不再集中在一起,如果此时再贸然使用memcpy()、memset()函数,那么所带来的后果将不可预计。

请记住:

要区分哪些数据对象是POD,哪些是非POD。由于非POD对象的存在,在C++中使用memcpy()系列函数时要保持足够的小心。
--------------------- 
作者:QQ51931373 
来源:CSDN 
原文:https://blog.csdn.net/qq51931373/article/details/50788059 
版权声明:本文为博主原创文章,转载请附上博文链接!

二、memcpy_s与memcpy比较

扫描二维码关注公众号,回复: 6224105 查看本文章

https://blog.csdn.net/summer_liuwei/article/details/50243015

void* memcpy( void *dest, const void *src, size_t count );

(until C99)

void* memcpy( void *restrict dest, const void *restrict src, size_t count );

(since C99)
errno_t memcpy_s( void *restrict dest, rsize_t destsz,
                  const void *restrict src, rsize_t count );
(2) (since C11)
     

1) Copies count characters from the object pointed to by src to the object pointed to by dest. Both objects are interpreted as arrays of unsigned char.

 The behavior is undefined if access occurs beyond the end of the dest array. If the objects overlap (which is a violation of the restrict contract) (since C99), the behavior is undefined. The behavior is undefined if eitherdest or src is a null pointer.

2) Same as (1), except that the following errors are detected at runtime and cause the entire destination range [dest, dest+destsz) to be zeroed out (if both dest and destsz are valid), as well as call the currently installed constraint handler function:

  • dest or src is a null pointer
  • destsz or count is greater than RSIZE_MAX
  • count is greater than destsz (buffer overflow would occur)
  • the source and the destination objects overlap

 The behavior is undefined if the size of the character array pointed to by dest < count <= destsz; in other words, an erroneous value of destsz does not expose the impending buffer overflow.

As all bounds-checked functions, memcpy_s is only guaranteed to be available if __STDC_LIB_EXT1__ is defined by the implementation and if the user defines __STDC_WANT_LIB_EXT1__ to the integer constant 1before including string.h.

相较于memcpy,memcpy_s会检查:

1) dest、src的合法性;

2)检查destsz、count的合法性;

3)检查缓存异常的风险;

4)检查目的buf和源buf是否存在内存覆盖。

猜你喜欢

转载自blog.csdn.net/martinkeith/article/details/89336529