memset函数的使用陷阱
memset是C/C++编程中常用的函数,一般用于申请内存后的初始化操作,比如:
1 | char* buffer = (char*)malloc(1024); |
memset接收三个参数:
- 第一个参数是开始填充的地址
- 第二个参数是填充的byte
- 第三个参数要填充的字节数(注意是字节数)
这个函数看似简单,但是如果使用不当则会导致一些未知的bug。以下是目前遇到的几个陷阱。
陷阱一:
memset是按字节赋值,虽然第二个参数是int类型,但有效值只取低位的一个字节。这也是为什么第三个参数强调的是填充的字节数而非填充长度,如下。
1
2
3
4int a[2];
memset(a, 0x1203, 2);
// expect: a = {0x00000003, 0x00000003}
// actual: a = {0x03030303, 0x03030303}使用建议:
- 最好只用于单字节数组的初始化,e.g., char[],uint8_t[]。这样不需要担心第二个或第三个参数的取值。
- 用于非单字节的数组的初始化时,第二个参数只能是0(b00000000)或-1(b11111111)。
陷阱二:
memset函数的第三个参数慎用sizeof的结果。
因为静态数组作为参数传入某个函数的时候,就会退化成指针,也就是该数组的首地址,其数组的长度信息就丢失。如下:
1
2
3
4
5
6int a[] = {1,2,3,4,5};
// sizeof(a) = 20
// 静态数组a退化成指针,因此sizeof的结果为4.
memset(s, 0, sizeof(a)/*the result = 4*/);
// expect: a = {0, 0, 0, 0, 0}
// actual: a = {0, 2, 3, 4, 5}