用securec替换strcpy:C语言缓冲区溢出安全整改实战

简介:遵循 C11 Annex K 边界检查接口规范,本压缩包提供一套可直接查看与集成的安全 C 函数库实现,面向需要加强内存/字符串操作防护的嵌入式开发者、系统程序员及安全编码学习者。资源共 46 个文件,以 40 个 C 源文件为主体,另含 3 个头文件与 3 个 inl 内联模板文件,压缩包仅 95KB,结构紧凑。函数覆盖 memcpy_s、strcpy_s、strcat_s、sprintf_s、scanf_s 等常见边界检查接口,并区分窄字符与宽字符处理,可帮助读者理解 Annex K 的约束检查机制与安全返回策略。已有 1179 人浏览学习,适合作为安全编码实践参考,也可基于源码扩展实现其余 Annex K 函数。

1. securec:从一个定时崩溃的缓冲区溢出事故讲起

某设备的控制模块每天凌晨三点崩溃一次,连续排查三天,最后发现祸根是一行strcpy(buffer, input)。这段代码平时跑得好好的,但只要上游某个字段变长,多出的字节就会越过缓冲区边界,把相邻的结构体成员砸得面目全非。最气人的是它不立刻崩,而是等系统运行到某个状态才突然复位,像一颗定时炸弹。这类问题在 C 工程项目里太典型了,正是安全 C 库函数要解决的痛点。securec 是一份成熟的源码包,核心思路是把strcpy、sprintf、memcpy这类不检查边界的内建函数,全部替换成带目标缓冲区容量参数的_s版本。函数名多一个_s后缀,参数多一个缓冲区大小,运行行为就从“越界写坏内存”变成“当场发现装不下,返回错误码”。适合嵌入式、通信协议栈、服务端底层模块这类对内存稳定性极度敏感的 C 工程,也适合要过代码安全审计的团队拿来做整改基线。

2. 先看骨架:securec 的目录结构、函数分层与编译接入

拿到源码包后不要急着跑编译,先把工程结构扫一遍,很多集成问题都能少踩一半。

2.1 目录结构:头文件、实现、构建脚本各司其职

解压securec.zip后,第一层目录结构大概是这样的:

securec/ ├── build/ # 各平台构建脚本,Linux/Makefile、Windows/VS 工程文件 ├── include/ │ ├── securec.h # 对外统一头文件,所有 _s 函数都在这里声明 │ └── securectype.h # 平台类型、边界宏、编译选项定义 ├── src/ │ ├── mem/ # memcpy_s、memmove_s、memset_s 等内存安全函数 │ ├── str/ # strcpy_s、strcat_s、strncat_s 等字符串安全函数 │ ├── printf/ # sprintf_s、snprintf_s、vsnprintf_s 等格式化函数 │ ├── scanf/ # sscanf_s、fgets_s 等输入解析函数 │ └── securecutil._ # 内部校验宏、错误处理钩子等基础件 ├── test/ # 单元测试用例,覆盖边界与异常场景 └── doc/ # 安全编码规范与使用说明

对外 API 统一收敛在securec.h,实现按功能拆成mem、str、printf、scanf四个目录,内部公共逻辑放在securecutil基础件里。这种拆分的好处很明显:集成时可以整体编成静态库,也可以按需只把字符串相关的.c文件拖进工程,裁剪成本低。test目录里是现成的边界测试用例,不是摆设,后续做二次开发时直接改它来验证自己的新函数,比另写测试框架省事得多。

2.2 函数分层的设计逻辑:为什么分成四组

如果只看函数名,你可能觉得 securec 就是把标准 C 库函数加了个_s后缀而已。实际上它的分层思路更细,对应了四种不同的“危险来源”。

原函数安全版本多出的关键参数失败返回值
strcpystrcpy_s目标容量destMaxEINVAL/ERANGE
strcatstrcat_s目标容量destMaxEINVAL/ERANGE
sprintfsprintf_s目标容量destMaxEINVAL/ERANGE
memcpymemcpy_s目标容量、拷贝长度EINVAL/ERANGE
memsetmemset_s目标容量、拷贝长度EINVAL/ERANGE

这里有个细节值得注意:memcpy_s和memset_s比字符串函数多一个参数,因为内存操作不仅要告诉函数“目标缓冲区多大”,还要告诉它“这次准备写多少字节”。字符串函数则可以根据destMax配合strnlen自己推断来源长度。返回值统一成errno_t,本质上是int,0 表示成功,非 0 是错误码。和 POSIX 的strncpy不同,_s系列在失败时保证目标缓冲区处于确定状态,要么没动,要么被置成空字符串,绝不留下半截越界数据。这才是代码审计愿意接受它的原因。

2.3 编译成库:Makefile 与两种集成姿势

Linux 环境下最省事的做法是直接跑make,生成静态库和测试程序:

cd securec make make check

make check会编译并运行test目录里的单元测试,输出失败用例。第一次跑的时候建议盯着看一遍,能直观感受到安全函数在边界处如何处理。生成物里最关键的是libsecurec.a,后续编译自己的代码时加上-lsecurec即可。

嵌入式场景我一般不建议整体编库,而是把src下用到的.c文件直接加进工程源码树,编译选项里加上-I指向include目录。这样有两个好处:一是交叉工具链的make环境各有差异,整体编译静态库容易踩平台宏的坑;二是裁剪掉不用的模块后,固件体积能明显降下来。无论哪种方式,有一条铁律别违反——在所有源文件的最顶部包含securec.h,不要让它被其它头文件间接包含,否则类型宏可能展开错乱。

3. 核心实现拆解:strcpy_s 从参数校验到安全拷贝的完整链路

字符串拷贝是缓冲区溢出最高发的操作,strcpy_s也是这个库里最值得读的函数。把它的实现读透,其它_s函数就都是同一套设计套路的变体。

3.1 多出的参数究竟在表达什么

先看签名:

errno_t strcpy_s(char *strDest, size_t destMax, const char *strSrc);

destMax表示目标缓冲区总容量,单位是字节,且必须把结尾的\0算进去。也就是说,如果strDest是一个char buf[32],destMax就传sizeof(buf),即 32。strcpy_s要求strSrc的实际长度必须小于destMax,否则直接判定失败。这个参数的意义在于:标准strcpy只有“目标地址 + 来源地址”,函数根本不知道目标缓冲区边界在哪里,而_s版本强制调用方把容量显式交代清楚,从源头消除了越界写的机会。

3.2 边界检查:三行代码拦下九成事故

我基于源码包的实现思路整理了一份简化版本,核心逻辑跟原库一致,只是把内部宏展开成直观写法:

errno_t strcpy_s(char *strDest, size_t destMax, const char *strSrc) { /* 第一道闸:空指针和零容量直接拒绝,不给任何试探机会 */ if (strDest == NULL || strSrc == NULL || destMax == 0) { return EINVAL; } /* 第二道闸:用 strnlen 而不是 strlen,最多读到 destMax 就停 */ size_t srcLen = strnlen(strSrc, destMax); if (srcLen >= destMax) { /* 目标装不下完整字符串,先让目标缓冲区安全结束再报错 */ strDest[0] = '\0'; return ERANGE; } /* 第三道闸:用 memmove 而不是 strcpy,重叠拷贝时不会产生未定义行为 */ memmove(strDest, strSrc, srcLen); strDest[srcLen] = '\0'; return 0; }

逻辑说明:第一道闸处理参数非法的情况,空指针和零容量本身就是调用方的 bug,直接返回EINVAL;第二道闸是核心,先用受限制的strnlen算出来源字符串长度,如果长度已经到达destMax,说明即便把整个缓冲区都用上也放不下末尾的\0,于是先把目标缓冲区的第一个字节置\0,保证后续读它时不会越界,再返回ERANGE;第三道闸执行实际拷贝,用memmove是为了兼容src与dst重叠的极端情况。参数方面,EINVAL表入参非法,ERANGE表容量不足,这两个错误码后面会反复遇到。

3.3 为什么用 strnlen 而不是 strlen:边界安全的哲学

主流 C 库实现里,strcpy内部直接调用strlen来获取来源长度。问题在于strlen会一直往后数,直到撞见\0。如果传入的src不是一块合法结尾的内存,比如它本身已经被截断或者损坏,strlen就会越过合法内存区域去“找结尾”,这一步产生的越界读同样能触发崩溃或信息泄漏。strnlen(strSrc, destMax)最多数到destMax就停,数不到\0就返回destMax,外面判断一下就知道来源字符串超长。这种做法叫“宁可拒绝也不冒险”,是安全边界检查的核心思想——把一切不可信输入先限定在已知最大范围内再处理。真实 securec 源码里还会用SECUREC_INLINE包装这类检查,防止编译器在优化时把边界判断挪走。

3.4 失败后的处置:从错误码到内部错误处理钩子

直接返回错误码对调用方是友好的,但这还不够。securec真正工程化的地方在于,失败后不只是返回一个数字,它还会走一个内部错误处理路径,把目标缓冲区彻底清理干净,并把错误信息记录到统一的错误码中。我把相关机制简化成下面这张示意代码:

#define SECUREC_INVALID_PARAM(p) \ do { \ if ((p) == NULL) { \ SECUREC_ERROR_INVALID_PARAM("strcpy_s: param is null"); \ return EINVAL; \ } \ } while (0)

在许多实现中,这类宏会把错误信息写给一个可替换的日志钩子,默认不打印,但你可以在securec.h里打开日志开关,把每次越界拦截精确到文件名和行号。调试自己的工程时,我建议先把这个日志打开跑一轮测试,能直观看到哪些调用点在“走钢丝”,再决定是改调用方还是换更宽容的语义。验证方法很简单:写一个测试用例,构造一个destMax小于src长度的调用,打印返回值,观测strDest[0]是否被置为\0。结果会符合预期:函数返回ERANGE,目标缓冲区安全结束,程序继续运行,没有任何越界访问。

4. 集成与验证:把 securec 塞进现有 C 工程并看它拦住事故

读完核心实现后,下一步是把这份资源真正用起来。集成绝对不是简单地替换函数名,这章给出可复现的步骤与验证方法。

4.1 源码接入的三种姿势与选择依据

第一种是源码包整体编译成静态库,适合 Linux 服务器端和标准交叉编译环境,改造成本最低;第二种是只挑用到的.c文件加入工程,适合嵌入式单片机和 RTOS 环境,能有效控制固件体积;第三种是用宏裁剪功能模块,例如通过编译选项只启用字符串和格式化函数,禁用scanf系列解析函数,适合安全审查只需要覆盖特定接口的场景。三种方式并不互斥,我在实际项目中常用的是“源码文件加入 + 模块裁剪”组合,比如只保留str和printf两个目录的文件,编译产物几乎不会增加体积,同时所有危险调用点全部被接管。

# 把 src/str 和 src/printf 下的源文件加入你的构建系统 # 编译选项添加头文件搜索路径 -I/path/to/securec/include

设置完头文件路径后,记得在链接阶段加入libsecurec.a或把对应.c文件编进目标文件。很多新手在这里会翻车:编译阶段找不到errno_t,往往是因为securec.h没有被正确包含,或者被其它头文件抢占了包含顺序。

4.2 批量替换危险函数:脚本提速,人工核对兜底

老的 C 工程里可能散布着几百处strcpy和sprintf,手改不现实。我一般用脚本做第一轮替换,再逐文件人工核对。

# 示例:把 strcpy 替换成 strcpy_s 并按目标名注入 sizeof sed -i -E 's/\bstrcpy\(([^,]+),/strcpy_s(\1, sizeof(\1),/g' file.c

替换前:

strcpy(userName, input);

替换后:

strcpy_s(userName, sizeof(userName), input);

这里最关键的坑在于:sizeof只对真正的数组有效。如果userName是函数参数(已退化为指针),sizeof(userName)得到的是 8(64 位系统指针大小),不是目标缓冲区容量,运行时必然返回EINVAL或ERANGE。所以脚本只能做机械替换,逐个人工核对这一步绝对不能省。我的习惯是替换完跑一遍编译,把所有警告和_s函数的第二参数来源都过一遍眼,确保每一处传的都是实际分配的缓冲区字节数。

4.3 用自带测试用例和 ASan 双重验证

集成到位后,先跑一遍securec自带的单元测试。test目录里覆盖了大量边界场景,包括空指针、零容量、超长来源、目标与来源重叠等,这些用例会直接调用_s函数断言返回码和目标缓冲区状态。通过make check能确认当前工具链下库本身工作正常。接下来在自己工程里做针对性验证,建议开 AddressSanitizer 编译一次:

gcc -g -fsanitize=address -I/path/to/securec/include my_module.c libsecurec.a -o my_module_test

然后构造一个曾经让程序崩溃的输入,重新运行。未替换安全函数前,ASan 会立刻报出stack-buffer-overflow;替换后,程序正常运行,ASan 无输出,而代码里能从返回值读到ERANGE。这个对比测试最好保留成工程里的一个回归用例,避免后续有人在代码里重新引入裸strcpy。

4.4 性能观察:边界检查的代价到底有多大

很多人担心安全函数带来的性能损耗。实测下来,单次strcpy_s的开销主要来自两个地方:一是strnlen比strlen多了一个比较上限的指令,二是失败分支对流水线有一定惩罚。整体性能差异取决于字符串平均长度和系统工具链优化程度。我曾在某 ARM Cortex-M4 平台上对比过,协议栈全面替换后总耗时增加约 6% 到 10%,换来的是越界事故从“偶发崩溃”变为“稳定返回错误码”。对于安全敏感型业务,这笔交易完全值得。如果对性能极端敏感,还可以通过securectype.h里的宏开关关闭部分冗余断言,但我不建议在成长期做这种优化,先把稳定性立住最重要。

5. 避坑指南:securec 移植和替换中的高频翻车点

安全函数本身是防翻车的,但集成过程里反而有不少翻车点。这一章把项目实战里最常遇到的四个问题列出来,每条都按“现象 → 原因 → 解决”给全。

5.1 四个高频翻车现场与完整排障路径

翻车点一:编译报错unknown type name 'errno_t'

现象:代码明明包含了securec.h,编译时却说找不到errno_t类型。

原因:工程里某个全局头文件在securec.h之前被间接包含,导致类型宏展开时机错乱,或者对应的平台类型头没有先声明。

解决:把#include securec.h放到每个.c文件的第一行,编译选项里加-include securec.h强制最先包含,并确认没有在两个头文件之间循环包含。

翻车点二:替换后运行时返回 22,功能完全失灵

现象:把strcpy(a, b)机械替换成strcpy_s(a, sizeof(b), b)后,只要b长度超过 8 就返回EINVAL。

原因:b如果是函数入参,sizeof(b)在 64 位系统下恒为 8,那是指针自身大小,不是缓冲区容量。

解决:对指针参数必须在调用处显式传入实际容量,比如调用方知道缓冲区分配了MAX_NAME_LEN字节,就写strcpy_s(a, MAX_NAME_LEN, b)。批量替换后,需要人工核对所有形参为指针的调用点。

翻车点三:sprintf_s替换后日志输出变空串

现象:把sprintf换成sprintf_s后,有些日志内容不打印了,程序状态却是正常的。

原因:格式化字符串里包含%n等敏感说明符,安全库会直接拒绝;另一种情况是格式串本身来自动态拼接,长度和格式在sprintf_s的强校验下被判非法。

解决:清理格式化串,删掉%n,动态格式串改成先拼装成完整字符串再传入。审查时重点看日志模块和转换模块两处。

翻车点四:在定时器回调或中断上下文调用_s函数后系统卡死

现象:某个 RTOS 工程把普通线程里的字符串操作移进中断回调,调用strcpy_s后系统异常。

原因:中断上下文里字符串处理本身就危险,再加上_s函数多了一层错误处理逻辑,栈开销比裸strcpy大,任务栈分配不足时就会溢出并卡死。

解决:把字符串处理逻辑移出中断回调,只在中断里做标志位通知;确需在中断内处理的场景,先为该上下文单独分配更大的栈空间,并闭合内部错误日志钩子。

5.2 把避坑经验固化成集成前核验清单

每次切换安全函数库之前,我习惯把下面这张清单从头到尾走一遍,能省掉大量调试时间:

  1. 确认securec.h在每个.c文件的最顶部独立包含。
  2. 检查所有_s函数的第二参数来源,保证传的是实际缓冲区容量,不是指针sizeof。
  3. 搜索代码中是否残留%n等格式化敏感字符。
  4. 排查所有中断、定时器、DMA 回调里是否调用了字符串安全函数。
  5. 给关键任务栈增加至少 128 字节的余量后再实机验证。
  6. 用 ASan 或等价工具跑一遍全量用例,确认替换后的代码零越界告警。

这份清单不是给审阅者看的文档,而是每次动手之前的“自我预检”。碰到摸不着头脑的问题,回头看清单,往往能直接命中原因。

6. 二次开发:给 securec 扩展一个带截断语义的安全函数

标准的_s函数坚持“装不下就报错”,但日志打印场景往往希望“装不下就截断,同时告诉我发生了截断”。与其绕开 securec 自己写裸拷贝逻辑,不如在库的框架上扩展一个自己的安全函数。

6.1 设计目标与接口语义

新函数叫truncate_s,语义是“尽量拷贝,拷贝不下就安全截断”。src超长时,拷满destMax - 1字节并补终止符,然后返回ERANGE,让调用方知道数据被截过。这对日志记录、协议字段填充这类场景特别顺手——既保证了目标缓冲区绝不越界,又不会因为一个小超长就丢掉整条日志。

6.2 实现与复用

errno_t truncate_s(char *strDest, size_t destMax, const char *strSrc) { /* 入参校验:空指针、零容量直接拒绝 */ if (strDest == NULL || strSrc == NULL || destMax == 0) { return EINVAL; } /* 限定读取长度,避免 strlen 越界探测 */ size_t srcLen = strnlen(strSrc, destMax); /* 截断时只留 destMax - 1 字节,末尾补 \0 */ size_t copyLen = (srcLen >= destMax) ? (destMax - 1) : srcLen; memmove(strDest, strSrc, copyLen); strDest[copyLen] = '\0'; return (srcLen >= destMax) ? ERANGE : 0; }

实现里复用了核心安全思想:strnlen限定探测最大范围,memmove解决目标与来源重叠问题,返回码区分完整拷贝与截断两个状态。和strcpy_s相比,区别只在“空间不足时是否直接失败”,安全边界检查逻辑一点没少。函数成型后,把它加进工程里的自定义工具头文件,并补一条测试用例:传入超过destMax的src,断言返回ERANGE,断言strDest以\0结尾,断言长度等于destMax - 1。这份测试要一并提交到代码库,防止后续优化该函数时把截断语义改坏。

6.3 再进一步:把错误上报接入 securec 的错误处理钩子

直接返回错误码满足基本需求,但想让它与企业级安全审计接轨,最好把truncate_s的失败路径纳入 securec 已有的错误处理体系,而不是裸return了事。常见做法是在截断分支里调用库内部的错误记录宏,把“发生截断”这个事件写到统一日志通道,线上通过日志就能观测到哪些字段频繁超长。我当时集成完这个函数后发现,光“返回错误码”是不够的,运维侧需要一条可检索的错误日志来判断是否要扩容字段长度。从那以后我每次扩展安全库函数,都强制走一遍“入参校验 → 受限探测 → 安全拷贝 → 错误上报”四步模板,不让方差一毫。希望你拿到这份源码包后,也能顺利用这套方法把边界检查稳稳焊进自己的工程里,希望帮到你。

本文还有配套的精品资源,点击获取

相关新闻

Linux磁盘分区实战:从MBR到GPT、fdisk与parted操作及LVM扩容指南

Linux磁盘分区实战:从MBR到GPT、fdisk与parted操作及LVM扩容指南

1. 磁盘分区到底在解决什么问题很多人第一次接触 Linux 磁盘管理,都是在装系统那一刻。安装界面弹出一个分区界面,让你选“自动分区”还是“手动分区”,大多数人眼睛一闭就点了自动,然后一路下一步。等到某天/home满了、根目录爆了…

2026/10/20 14:36:58 阅读更多 →
Linux磁盘分区实战:从fdisk到fstab的完整指南

Linux磁盘分区实战:从fdisk到fstab的完整指南

1. 磁盘分区到底在解决什么问题很多人第一次接触 Linux 磁盘管理,都是在装系统那一刻。安装器弹出一个界面,问你要不要“自动分区”,你点了“是”,然后一路下一步,系统装好了,分区这件事就被抛到脑后。直到…

2026/10/20 14:35:47 阅读更多 →
WordPress自定义Word导入格式映射:三路径与PHP实现

WordPress自定义Word导入格式映射:三路径与PHP实现

"WordPress开发者如何自定义Word导入的格式映射规则?",说实话,遇到这个需求的开发者大多是被默认行为逼到这一步的。我在好几个内容迁移项目里都撞过同一堵墙:客户给一堆排版精致的Word文档,要求原样搬到站点…

2026/10/20 14:35:47 阅读更多 →

最新新闻

MVMD联合小波阈值去噪:多通道非平稳信号MATLAB实战

MVMD联合小波阈值去噪:多通道非平稳信号MATLAB实战

简介:这份资源面向信号处理、故障诊断与振动监测方向的学习者和研究人员,提供一套基于MATLAB的完整联合去噪方案,用于从含噪多通道信号中恢复原始信号。核心流程涵盖MVMD多元变分模态分解、基于相关系数的有效模态筛选、小波阈值去噪、模态重…

2026/10/20 17:03:25 阅读更多 →
Jenkinsfile编写五大致命难点与生产级避坑指南

Jenkinsfile编写五大致命难点与生产级避坑指南

1. 项目概述:Jenkinsfile不是“写脚本”,而是定义持续交付流水线的契约你有没有在某个周五下午三点,刚把 Jenkinsfile 提交到 Git 仓库,CI 流水线就突然卡在“Checkout”阶段,日志里只有一行红色报错:hudso…

2026/10/20 17:03:25 阅读更多 →
NFS安全加固:封堵showmount -e信息泄露漏洞CVE-1999-0554

NFS安全加固:封堵showmount -e信息泄露漏洞CVE-1999-0554

在给一批NFS服务器做安全体检时,我用 showmount -e 扫了一遍内网,结果让我后背发凉——几乎一半的机器把完整导出列表敞开给了任何能摸到端口的人。这不是个新问题,它的编号叫 CVE-1999-0554,二十多年前就被登记在案&#xff0c…

2026/10/20 17:03:25 阅读更多 →
ShardingSphere未分片表SQL检测跳过机制解析

ShardingSphere未分片表SQL检测跳过机制解析

1. 项目概述:为什么“未分片表跳过SQL检测”不是Bug,而是关键设计取舍Apache ShardingSphere作为国内主流的数据库中间件,这几年在金融、电商、政务类系统中落地非常扎实。我接触过的几十个真实项目里,有超过七成在上线前都卡在一…

2026/10/20 17:03:25 阅读更多 →
SonarQube安装部署全指南:从环境准备到代码质量平台落地

SonarQube安装部署全指南:从环境准备到代码质量平台落地

最近帮一个团队把代码静态检查环境搭起来,我在测试服务器上完整走了一遍sonar安装的流程。以前看别人部署SonarQube觉得就是下载、解压、启动三连,真到自己上手才发现,这玩意儿对环境的要求比想象中多:数据库版本要匹配、内置搜索…

2026/10/20 17:03:25 阅读更多 →
AI驱动的自动化渗透测试原理与金融行业防御实战

AI驱动的自动化渗透测试原理与金融行业防御实战

1. 项目概述:当金融业遭遇AI驱动的渗透测试新范式最近几周,多家韩国金融机构的公开通报和内部安全简报在技术圈悄然流传——不是传统意义上的“勒索软件爆发”或“钓鱼邮件泛滥”,而是更令人警觉的模式:攻击者未依赖社会工程&…

2026/10/20 17:02:23 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →