memset, memset_s

< c‎ | string‎ | byte
定义于头文件 <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) ,除了若 destdestsz 自身有效,则存储 ch 于目标范围 [dest, dest+destsz) 的每个位置后,在运行时检测下列错误,并调用当前安装的制约处理函数:
  • dest 是空指针
  • destszcount 大于 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

参阅

将一个缓冲区复制到另一个
(函数)
将给定的宽字符复制到宽字符数组的所有位置
(函数)