memset, memset_s
定义于头文件 <string.h>
|
||
void *memset( void *dest, int ch, size_t count ); |
(1) | |
errno_t memset_s( void *dest, rsize_t destsz, int ch, rsize_t count ); |
(2) | (C11 起) |
1) 复制值
ch
(如同以 (unsigned char)ch 转换到 unsigned char 后)到 dest
所指向对象的首 count
个字节。 若出现 dest 数组结尾后的访问则行为未定义。若
dest
为空指针则行为未定义。2) 同 (1) ,除了若
dest
与 destsz
自身有效,则存储 ch
于目标范围 [dest, dest+destsz) 的每个位置后,在运行时检测下列错误,并调用当前安装的制约处理函数:
-
dest
是空指针 -
destsz
或count
大于 RSIZE_MAX -
count
大于destsz
(会发生缓冲区溢出)
-
若
dest
所指向的字符数组大小 < count
<= destsz
; 则行为未定义,换言之,错误的 destsz
值不暴露行将发生的缓冲区溢出。
- 同所有边界检查函数,
memset_s
仅若实现定义了 __STDC_LIB_EXT1__ ,且用户在包含string.h
前定义 __STDC_WANT_LIB_EXT1__ 为整数常量 1 才保证可用。
参数
dest | - | 指向要填充的对象的指针 |
ch | - | 填充字节 |
count | - | 要填充的字节数 |
destsz | - | 目标数组的大小 |
返回值
1)
dest
的副本,本质为更底层操作的临时内存地址,在实际操作中不建议直接使用此地址,操作完成以后,真正有意义的地址是dest本身。2) 成功时为零,失败时为非零。在失败时,若
dest
不是空指针且 destsz
合法,则亦写入 destsz
个填充字节 ch
到目标数组。注意
若 memset
所修改的对象在其生存期的剩余部分不再被访问,则此函数可以被优化掉(在如同规则下)(例如 gcc 漏洞 8537 )。为此,此函数不能用于擦洗内存(例如以令填充存储密码的数组)。对 memset_s
禁止此优化:保证进行内存写。该问题的第三方解决方案包含 FreeBSD explicit_bzero 或 Microsoft SecureZeroMemory 。
示例
运行此代码
#define __STDC_WANT_LIB_EXT1__ 1 #include <stdio.h> #include <string.h> #include <stdlib.h> int main(void) { char str[] = "ghghghghghghghghghghgh"; puts(str); memset(str,'a',5); puts(str); #ifdef __STDC_LIB_EXT1__ set_constraint_handler_s(ignore_handler_s); int r = memset_s(str, sizeof str, 'b', 5); printf("str = \"%s\", r = %d\n", str, r); r = memset_s(str, 5, 'c', 10); // count 大于 destsz printf("str = \"%s\", r = %d\n", str, r); #endif }
可能的输出:
ghghghghghghghghghghgh aaaaahghghghghghghghgh str = "bbbbbhghghghghghghghgh", r = 0 str = "ccccchghghghghghghghgh", r = 22
引用
- C11 standard (ISO/IEC 9899:2011):
- 7.24.6.1 The memset function (p: 371)
- K.3.7.4.1 The memset_s function (p: 621-622)
- C99 standard (ISO/IEC 9899:1999):
- 7.21.6.1 The memset function (p: 333)
- C89/C90 standard (ISO/IEC 9899:1990):
- 4.11.6.1 The memset function
参阅
(C11) |
将一个缓冲区复制到另一个 (函数) |
(C95) |
将给定的宽字符复制到宽字符数组的所有位置 (函数) |