memset和memcpy是两个常见函数,用于处理内存块的操作。
memset函数
memset函数用于将一块内存区域的内容设置为特定的值。
函数原型为:void* memset(void* ptr, int value, size_t num);
其中:
- ptr:指向要填充的内存块的指针。
- value:要设置的值。
- num:要设置的字节数。
函数功能描述:该函数将ptr指向的内存块中前num个字节设置为value。
注意事项:
- memset 并不对指针 ptr 指向的内存区域做边界检查,因此使用时需要确保 ptr 指向的内存区域足够大,避免发生越界访问。
- memset 的第二个参数value通常是一个 int 类型的数值,但实际上函数实现中只使用了该数值的低8位。这意味着如果传入0~255之外的其他数值可能会产生未定义的行为。
- num 参数通常是通过sizeof 等计算函数得到的。
常见用法就是将内存块快速置0,例如:
char auc_buff[64] = { 0 };
char str1[32] = { 0 };
char str2[32] = { 0 };
// set_static_string函数为自定义函数,功能类似memcpy,将auc_buff传入str
get_value(SYS_CONFIG, "info.id", auc_buff, sizeof(auc_buff)) //获取值
set_static_string(auc_buff, str1, sizeof(str1));
memset(auc_buff, 0, sizeof(auc_buff)); //将缓冲池置0,为下次读写做准备
get_value(SYS_CONFIG, "info.sid", auc_buff, sizeof(auc_buff))
set_static_string(auc_buff, str2, sizeof(str2));
memset(auc_buff, 0, sizeof(auc_buff));
......
错误示范:
因为函数实现中第二个参数 value 只使用了低8位。如果使用 int 类型的变量进行赋值,使用除 -1 和 0 以外的其他整数会出现问题。例如使用 1 进行赋值,1 的二进制表示为 0000 0001,使用 memset(num, 1, sizeof(num)) 进行赋值时memset函数初始化每个字节为:0000 0001, 0000 0001, 0000 0001...此时前4字节组成 int 整数时为:16843009 而非1。
造成这种现象的原因主要是 memset 函数在做初始化的时候是以 字节(byte) 为单位的,也就是 8 位二进制数。由于 bool 和 char 类型的变量都是 1 字节,所以使用 bool 和 char 类型进行初始化的时候不会出现问题,但使用 int 类型进行初始化一定要注意这个问题。当然,使用 int 类型进行初始化一般用作快速置0,使用 -1 和 0 时并不会出现问题。
memcpy函数
memcpy函数用于将源内存区域内容复制到目标内存区域,不可以处理重叠的内存区域。
函数原型为:void* memcpy(void* dest, const void* src, size_t num);
其中:
- dest:指向目标内存区域的指针。
- src:指向源内存区域的指针。
- num:复制的字节数
函数功能描述:该函数将 src 指向内存区域的 num 字节复制给 dest 指向的内存区域。
注意事项:
- 确保目标内存区域足够大,注意 num 的大小设置,一般用 sizeof(dest) 进行表示,避免出现dest 内存溢出的情况。
- memcpy 函数可以处理任意类型的内存块,在涉及指针类型转换时,要确保转换的正确性,避免发生未定义行为。
内存溢出举例:
char info_config[100];
char info_svn[50];
//如果使用sizeof(info_config)会造成info_svn的内存溢出
memcpy(info_svn, info_config, sizeof(info_svn));
如果需要处理内存重叠的情况,可以考虑使用 memove 函数。
memset 与 memcpy 的区别
- memset 只对一个内存区域有操作,用于设置内存块的值;memcpy 有两个内存区域参与,用于复制内存块的值。
- memset 将整个内存块设置成指定值;memcpy 只会对内存块中指定大小的区域产生影响。
值得注意的是两个函数都是基于字节进行操作,在使用过程中要谨慎处理内存边界和类型转换问题,以避免出现意外行为造成不可预知的错误。