Namespaces
Variants

memset, memset_explicit, memset_s

From cppreference.net
< c ‎ | string ‎ | byte
定义于头文件 <string.h>
void * memset ( void * dest, int ch, size_t count ) ;
(1)
void * memset_explicit ( void * dest, int ch, size_t count ) ;
(2) (C23 起)
errno_t memset_s ( void * dest, rsize_t destsz, int ch, rsize_t count ) ;
(3) (C11 起)
1) 将值 ( unsigned char ) ch 复制到 dest 所指向对象的前 count 个字符中。
若访问超出目标数组末尾,则行为未定义。若 dest 为空指针,则行为未定义。
2) (1) 相同,但对敏感信息安全。
3) (1) 相同,区别在于以下错误会在运行时被检测到,并在目标范围 [ dest, dest + destsz ) 的每个位置存储 ch 后(若 dest destsz 自身有效),调用当前安装的 约束处理函数
  • dest 是空指针
  • destsz count 大于 RSIZE_MAX
  • count 大于 destsz (将发生缓冲区溢出)
dest 所指向的字符数组大小满足 < count <= destsz ,则行为未定义;换言之, destsz 的错误值不会暴露即将发生的缓冲区溢出。
与所有边界检查函数一样,仅当实现定义了 __STDC_LIB_EXT1__ 且用户在包含 <string.h> 前将 __STDC_WANT_LIB_EXT1__ 定义为整型常量 1 时,才保证 memset_s 可用。

目录

参数

dest - 指向要填充对象的指针
ch - 填充字节
count - 要填充的字节数
destsz - 目标数组的大小

返回值

1,2) dest 的副本
3) 成功时返回零,错误时返回非零值。在发生错误时,如果 dest 不是空指针且 destsz 有效,则向目标数组写入 destsz 个填充字节 ch

注释

memset 可能会被优化掉(根据 as-if 规则),如果通过此函数修改的对象在其剩余生命周期内不再被访问(例如 gcc bug 8537 )。因此,此函数不能用于擦除内存(例如将存储密码的数组填充为零)。

此优化对 memset_explicit 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 is greater than destsz  
    printf("str = \"%s\", r = %d\n", str, r);
#endif
}

可能的输出:

ghghghghghghghghghghgh
aaaaahghghghghghghghgh
str = "bbbbbhghghghghghghghgh", r = 0
str = "ccccchghghghghghghghgh", r = 22

参考文献

  • C17 标准 (ISO/IEC 9899:2018):
  • 7.24.6.1 memset 函数 (p: 270)
  • K.3.7.4.1 memset_s 函数 (p: 451)
  • C11 标准 (ISO/IEC 9899:2011):
  • 7.24.6.1 memset 函数 (p: 371)
  • K.3.7.4.1 memset_s 函数 (p: 621-622)
  • C99标准(ISO/IEC 9899:1999):
  • 7.21.6.1 memset函数(页:333)
  • C89/C90 标准 (ISO/IEC 9899:1990):
  • 4.11.6.1 memset 函数

参见

复制一个缓冲区到另一个缓冲区
(函数)
(C95)
将给定的宽字符复制到宽字符数组的每个位置
(函数)
C++ 文档 关于 memset