Cracking C++(12): 实现 memset

news/2024/11/29 13:50:21/

文章目录

    • 1. 目的
    • 2. memset: API 说明
      • 2.1 查询 man 文档
      • 2.2 为什么使用 `int` 类型传入填充值 `c`?
      • 2.3 为什么需要返回值?
    • 3. memset: naive 实现
      • 3.1 byte-wise 的实现
      • 3.2 加速实现: word-wise
      • 3.3 其他实现
    • 4. References

1. 目的

最近了解到 deepdream_c 这个开源项目, 作者用 C89 实现了 deepdream. 没错, C89 是30年前的技术了, 但作者仍用它完整了算法的实现, 可以说非常克制了。

受到作者风格的影响, 我在用 C99 实现 lenet, 涉及到相关 API 的使用我也尽可能的克制自己。不禁要问: 如果不使用 #include <string.h>, 能否自行实现 memset() 函数呢?

2. memset: API 说明

2.1 查询 man 文档

man memset
MEMSET(3)                     Library Functions Manual                     MEMSET(3)NAMEmemset – fill a byte string with a byte valueLIBRARYStandard C Library (libc, -lc)SYNOPSIS#include <string.h>void *memset(void *b, int c, size_t len);DESCRIPTIONThe memset() function writes len bytes of value c (converted to an unsignedchar) to the string b.RETURN VALUESThe memset() function returns its first argument.

2.2 为什么使用 int 类型传入填充值 c

查看 memset 文档,函数原型:

 void * memset(void *b, int c, size_t len);

而直觉认为应该是这样才对:

 void * memset(void *b, char c, size_t len);

参数 c 为什么用 int 类型而不是 int 类型呢?因为 memset() 函数在 C 语言很早期就存在了,那时候没有 function prototype, 而没有 function prototype 的情况下, 不能传入 char 类型。如果你强行传 char 类型, 就会自动提升为 int 类型。因此,那时候定义 memset 函数, 参数 c 用的就是 int 类型。 后来, C 语言逐渐完善, 需要先声明函数再使用, 这时候确实用 char c 更合适。(参考[1])

2.3 为什么需要返回值?

参考[3] 解释认为, memset() 可用于链式使用:

char a[200];
strcpy(memset(a, 0, 200), "bla");

In order to use the function as an argument for another function such as sprintf

也就是说, 直接把 memset(x, y, z) 作为另一个函数的参数。

3. memset: naive 实现

3.1 byte-wise 的实现

了解了 int c 参数的历史后, 我们知道参数 c 的实际有效值仅仅是最后1个byte, 因此写出正确实现:

void* memset(void* s, int c, size_t n)
{char* p = (char*)s;char x = c & 0xff; // most machines (PC, Android) are little-endian.for (size_t i = 0; i < n; i++){p[i] = x;}return s;
}

3.2 加速实现: word-wise

每次写入4个字节(uint32_t类型), 不足4字节的部分,逐字符拷贝。参考了文献[4].

void memset(void* s, int c, size_t n)
{uint32_t* p = (char*)s;// most machines (PC, Android) are little-endian.uint32_t x = c & 0xff;uint32_t xx = x;xx |= (xx << 8);xx |= (xx << 16);int nn = n >> 2;int remain = n - (nn << 2);size_t i = 0;fsor (; i < nn; i++){*p = x;p++;}char* q = (char*)p;for (; remain; remain--){*q = x;q++;}return s;
}

说明: xx |= (xx << 8) 把 xx 左移8位,累加到 xx 上。再执行 xx |= (xx << 16) 则等于原始的 xx 作为一个 byte 拷贝了4份放入到了一个 uint32 长度的内存中, 相当于 xx xx xx xx.

3.3 其他实现

可以用 SIMD 加速,暂时没尝试。

4. References

  • [1] Why does memset take an int instead of a char?
  • [2] Why does memset take in an int instead of an unsigned char?
  • [3] What’s the use of memset() return value?
  • [4] https://github.com/Smattr/memset/blob/master/memset.c

http://www.ppmy.cn/news/437576.html

相关文章

大数据可视化项目接口文件

文章目录 默认根路径 1.获取每月平均值接口功能URL支持格式HTTP请求方式请求参数返回字段接口示例 2.获取省份每月平均aqi接口功能URL支持格式HTTP请求方式请求参数返回字段接口示例 3.查询所有污染物平均值接口功能URL支持格式HTTP请求方式请求参数返回字段接口示例 4.成都市温…

【干货】Android系统定制基础篇:第二部分

1、Android Launcher3支持键盘切换焦点 Android Launcher3 默认并不支持键盘操作&#xff0c;无法切换焦点&#xff0c;在一些需要支持键盘或遥控操作的设备中无法使用&#xff0c;因些对 Launcher3 做简单修改&#xff0c;使其支持键盘切换焦点。 diff --git a/packages/app…

设置 HP Laser 108w网络打印机固定IP地址

打印机通电状态下&#xff0c;按住进纸键不松手&#xff0c;大概10几秒&#xff0c;灯闪烁时&#xff0c;松手&#xff0c;打印机会打印出两张纸&#xff0c;上面内容有这台机器的序列号&#xff0c;无线信号&#xff0c;密码等相关信息 打开电脑的 wifi &#xff0c;找到 DIR…

hp打印机被识别为了usb大容量存储

昨天下午遇到一个奇葩问题&#xff0c;哎&#xff0c;折腾了一个下午&#xff0c;hp1136型号打印机接到台式机上后被识别为了usb大容量存储&#xff0c;你要问我怎么知道的&#xff0c;到设备管理器里面看看就知道了&#xff0c;这样就导致打印机安装不了&#xff0c;就算侥幸安…

软件工程导论期末急救包(上)

目录 什么是软件工程&#xff1f;它的目标和内容是什么&#xff1f; 软件文档作用及包含 软件过程模型 瀑布模型 快速原型模型 增量模型 螺旋模型 喷泉模型 软件生存周期 需求分析阶段的基本任务是什么&#xff1f; 可行性研究的任务是什么&#xff1f; 软件是什…

《分布式中间件技术实战:Java版》学习笔记(一):抢红包

数据库建表 (1)red_send_record 记录用户发送了若干总金额的若干个红包。 CREATE TABLE red_send_record (id int(0) NOT NULL AUTO_INCREMENT,user_id int(0) NOT NULL COMMENT 用户id,red_packet varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL…

分布式驱动电动汽车定速巡航控制

目录 前言 1. 电机模型 1.1电机数学模型 1.2 电机传递函数模型 2. 控制器设计

【Proteus仿真】51单片机+8255A IO扩展例程

【Proteus仿真】51单片机+8255A IO扩展例程 📍相关参考:51单片机8255A扩展IO口🎬Proteus仿真演示: 📓8255A与51单片机连接 🌿51单片机的P0口作为数据总线使用,与8255A的D7~D0数据信号线进行连接,当P00 - P07不作为8255A 的A、B、C端口地址使用时,可以不接上拉电阻…