【C++】memset用法浅析(一)

memset 是 c/c++ 中的一个内存清洗函数。因为是直接修改内存中的字节值,所以更偏向于底层。这篇文章简单介绍下它的用法。

从字符串开始

这是 Visual Studio 对 memset 的介绍:

void *memset(
   void *dest,
   int c,
   size_t count
);

其中:

参数解释
dest指向目标的指针。
c要设置的字符。
count字符数。

作用是将 dest 的前 count 个字符设置为字符 c。我们举一个非常简单的例子:
这个函数将 char 数组的前 4 位设置为 *

#include <memory.h>
#include <cstdio>

int main( void )
{
   char buffer[] = "This is a test of the memset function";

   printf( "Before: %s\n", buffer );
   memset( buffer, '*', 4 );
   printf( "After:  %s\n", buffer );
}

输出如下:

Before: This is a test of the memset function
After:  **** is a test of the memset function

char 和 ASC|| 码在某些情况下是通用的,所以这里也可以写成

memset( buffer, 42, 4 );

效果是一样的。

如果不是字符串呢?

上面只是 memset 最常用的用法。事实上,memset 的正确解释是:

转换值 c 为 unsigned char 并复制它到 dest 所指向对象的首 count 个字节。

每个 char 占用 1 个字节,所以 4 个字节就是 4 个 char,也就是 char 数组的前 4 个元素。这没什么问题。但如果把 char 换成 int 呢?

先定义一个两个元素的 c 数组。

count 溢出

   int buffer[2];
   for(int a:buffer) {printf("before a = %d\n",a);}
   memset( buffer, 42, 4 );
   for(int a:buffer) {printf("after a = %d\n",a);}

将数组 buffer 的前 4 个字节赋值为 42,也就是二进制下的 101010,结果如下

before a = 0
before a = 0
after a = 707406378
after a = 0

707406378 的二进制为00101010 00101010 00101010 00101010(方便分析,我在前面补了0,下同),原因是,每个字节有 8 位,每一位都赋值为 42.我们试试赋值前 5 个字节。

after a = 707406378
after a = 42

42本身是填不满一个字节的,所以前6个字节的时候,值就有变化了。

after a = 707406378
after a = 10794

10794 的二进制为00101010 00101010,与预期也基本相符。
同样,memset 存在 count 大于 dest 的 size 的溢出可能性,这种行为的处理是未定义的。在我用的 TDM-gcc 9.2.0 中,全填充以后正常运行,不会报错。

memset( buffer, 42, 10 );
after a = 707406378
after a = 707406378

c 溢出

我们尝试赋值一个超过 8 位的int,也就是大于255(11111111

memset( buffer, 256, 4 );

结果如下:

after a = 0
after a = 0

256 的二进制表示为 1 00000000,显然,memset 只取了低 8 位。

更安全的 memset_s

本来这段是要介绍 memset_s 的,但是我的编译器怎么也无法编译成功网上的代码。

起初我以为是编译器不支持 C++ 11,或者支持但没有打开。后来我看到这篇文章:https://blog.csdn.net/StoryZX/article/details/123866245

这类所谓的’安全’函数没最初是由微软( Microsoft )为 Windows 平台实现的,其官方名字为 Safe C Library,见其官网 ,这里有这些函数的详细介绍,以及函数实现的文件依赖图( Include dependency graph )。但是有很多组织机构是反对将这些纳入 C 标准库中的,尽管最终微软说服 C 标准委员会( C standard committee) 将这些函数加入附录 K 中,但是这些函数仍然不是标准库的一部分。这些’安全’函数从 C11 标准才开始支持,但似乎也仅限于 MSVC (微软的 VC 运行库)。以上,大概就能够解释为什么官方手册中给的示例程序在自己的 Linux 开发机中无法编译、运行,即便引入了 srting.h 头函数,即便你在程序中定义了文档中所说必须的宏,也还是会显示找不到 memcpy_s 函数的定义。如果你真的去查找了一遍,就会发现,string.h 文件中根本没有对应的这些函数。至此,你可以理解为,这一类所谓更安全的函数,是微软的 VC 运行库中的函数,对于其他平台,默认并不支持,当今强制推广这些安全函数的只有 Windows 平台。(啊这,微软写的,自己不得给自己捧场。)

在我的 VSCode 里,被兼容性 if 包裹的这部分代码是灰色的。
在这里插入图片描述
一旦去掉 ifdef,就会报没有定义的错误。

还好,我电脑上有安装 VS 2022,我会在下一篇文章将编译器更换为 MSVC,或者使用 VS 2022 继续运行代码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值