目录
一.前言
二. memcpy模拟实现
三. memmove模拟实现
四.memcmp模拟实现
一.前言
计算机内存的实质就是以字节为编号单元的二进制序列集合,操作内存时我们应具有这样的视角。
二. memcpy模拟实现
库函数memcpy函数首部:void *memcpy( void *dest, const void *src, size_t num );
函数的功能是将src(数据源)指向的内存空间中的前num个字节的二进制序列拷贝到dest(目的空间)指向的前num个字节的内存空间中。拷贝完成后,函数会返回目的空间的首地址。
void*类型的指针变量可以用于接收任何类型的地址。
void*类型的指针不能直接解引用,也不能直接进行运算(只能进行赋值,但不能自增或自减).若要对void*类型指针进行解引用或运算,必须对其进行强制类型转换,由于内存是以1个字节为单位的,所以大多数情况下我们一般将其强制转换为char*的指针后进行解引用和运算。
(char*指针的访问权限和运算单位恰好为一个字节,符合我们进行内存操作的要求)
模拟实现:
void* my_memcpy( void* dest, const void* src, size_t num) { assert(dest && src); if (dest == src) { return dest; } void* ret = dest; while (num--) { *((char*)dest) = *((char*)src); dest = (char*)dest + 1; src = (char*)src + 1; } return ret; }
三. memmove模拟实现
当拷贝的目的内存空间和数据源空间有重叠部分时,若调用上面的memcpy函数在如下情况中就会出现问题。(假设我们要拷贝20个字节(num=20)的数据内容(vs2022一个整形四个字节))
很显然重叠部分的数据会丢失。
由此C标准库给出了memmove函数。
memmove函数首部:void *memmove( void *dest, const void *src, size_t num );
函数的功能描述与memcpy基本相同,但多了一句话“If some regions of the source area and the destination overlap, memmove ensures that the original source bytes in the overlapping region are copied before being overwritten”意思是当数据源内存空间与拷贝目的空间有重叠部分时,函数可以保证重叠部分数据在被覆盖前完成拷贝。
为了实现当dest指向空间和src指向空间有重叠部分时的数据的拷贝,memmove在设计时需分以下两种情况讨论:
显然区分上述两种情况的条件是指针src和dest的大小关系。
当src<dest,进行拷贝操作时我们需要从数据源空间的前num个字节的最后一个字节(从后向前)开始逐个字节拷贝到目标空间的前num个字节的相应空间中。
当src>dest,进行拷贝操作时我们需要从数据源空间的前num个字节的第一个字节(从前向后)开始逐个字节拷贝到目标空间的前num个字节的相应空间中。
需要注意的是,当dest指向空间和src指向空间无重叠部分时,上述两种拷贝顺序都是可以使用的。
memmove模拟实现:
void* my_memmove(void* dest, void* src, size_t num) { assert(dest && src); if (dest == src) { return dest; } void* ret = dest; if (dest > src) //从src空间的最后一个字节开始拷贝到dest空间的前num个字节中 { while (num--) { *((char*)dest + num) = *((char*)src + num); } return ret; } else //从src空间的第一个字节开始拷贝到dest空间的前num个字节中 { while (num--) { *((char*)dest) = *((char*)src); dest = (char*)dest + 1; src = (char*)src + 1; } return ret; } }
四.memcmp模拟实现
memcmp函数首部:int memcmp( const void *buf1, const void *buf2, size_t num );
函数功能是,将buf1指向的内存空间中前num个字节的二进制序列与buf2指向的内存空间中前num个字节的内容进行比较。
memcmp函数模拟实现:
int my_memcmp(const void* arr1, const void* arr2,size_t num) { assert(arr1 && arr2); while (num && *(char*)arr1 == *(char*)arr2) { arr1 = (char*)arr1 + 1; arr2 = (char*)arr2 + 1; num--; } if (num) { return *(unsigned char*)arr1 - *(unsigned char*)arr2; } else { return 0; } }
注意一个细节:返回值中的强制转换类型为unsigned char*。这里不用char*的原因如下:
比如我们比较的是两个空间的4个字节的内容,两块空间中分别存放了一个整形数据,arr1中存放的整形为128,arr2中存放的整形为1,(假设机器为小端机器),在比较arr1和arr2首字节序(前八个二进制位时)如果函数返回值写成return *(char*)arr1 - *(char*)arr2;*(char*)arr1会被认为是负数(整形128的前八位二进制序列为10000000截断后作为有符号char代表-128),这时函数返回值就是一个负数,与我们预期的结果不同,返回值中的强制转换类型为unsigned char就不会出现类似的问题。