在日常的工作中,通常需要使用到memset和memcpy进行内存的拷贝或者初始化。函数的原型如下:
void * memcpy(void *dest, const void *src, size_t len);
void * memset(void * buffer, int c, size_t num);
这样,任何类型的指针都可以传入 memcpy 和 memset 中,这也真实地体现了内存操作函数的意义, 因为它操作的对象仅仅是一片内存, 而不论这片内存是什么类型。这样来看,只要在使用的过程中,目标地址和源地址只要大小相同,即可实现内存的拷贝。接下来看下这两个函数实际的实现:
void *memcpy(void *dest, const void *src, size_t n)
{
char *dp = dest;
const char *sp = src;
while (n--)
*dp++ = *sp++;
return dest;
}
void *memset(void *s, int c, size_t n)
{
unsigned char* p=s;
while(n--)
*p++ = (unsigned char)c;
return s;
}
在实际的实现过程中,将传入的void型指针赋值给char型指针,按字节进行内存的拷贝。如果传入的指针数据类型不相同,按照字节进行拷贝将会发生错误:
short src[5] = { 1,2,3,4,5 };
short dest[5];
memcpy(dest, src, sizeof(src));
执行以上操作,正确完成十个字节的拷贝,结果如下:
1
2
3
4
5
请按任意键继续. . .
更改操作如下:
char src[5] = { 1,2,3,4,5 };
short dest[5];
memcpy(dest, (short *)src, sizeof(dest));
试图对src指针进行强制类型转换,无法得到正确的结果,因为函数的输入是一个void型指针,在内部进行了char型指针的转换。
正确的拷贝方法:
char src[5] = { 1,2,3,4,5 };
short dest[5];
char *psrc = src;
for (char i = 0; i < 5; i++)
{
dest[i] = *psrc++;
}
在memset函数中,同样是对传入的参数进行了类型的转换,按照单个字节进行拷贝。那么,我们在使用memset函数进行内存初始化的时候,如果初始化为0,不需要关注传入的指针类型,如果初始化一个字节为0xFF,或者两个字节0XFFFF,也都不需要关注指针类型,但是如果初始化为一个常数,则需要注意单个字节拷贝有可能引起的错误,比如:
char src[5];
memset(src, 1, sizeof(src));
char型正确拷贝
short src[5];
memset(src, 1, sizeof(src));
short型则出现拷贝错误,输出结果是257,原因是按照单个字节拷贝,实际拷贝数据为0X0101。在使用memset进行内存初始化操作时,应当注意这个问题。
note:
本文中函数原型参考维基百科:
https://clc-wiki.net/wiki/Main_Page