嵌入式开发-memcpy与memmove 技术详解

嵌入式开发-memcpy与memmove 技术详解 一、内存拷贝基础概念内存拷贝是嵌入式开发中最基础、最高频的数据操作核心作用是将一段连续内存空间的数据完整原样搬运到另一段内存空间中。广泛应用于数组数据复制、结构体赋值、缓冲区数据搬运、外设数据缓存、数据移位等场景。嵌入式开发中内存拷贝的核心判定标准为内存地址是否重叠这也是区分 memcpy 和 memmove 两个核心函数的关键依据合理选择函数可有效避免数据错乱、内存踩踏、程序死机等问题。二、memcpy 函数详解2.1 函数原型void *memcpy(void *dest, const void *src, size_t n);2.2 参数与返回值说明dest目标内存地址数据拷贝的存放位置src源内存地址待拷贝的数据源添加 const 修饰保证源数据只读不可修改n需要拷贝的字节数量返回值目标内存地址的指针支持链式调用2.3 核心特性无内存重叠处理逻辑仅支持无重叠内存拷贝内存重叠时拷贝结果不可控极易出现数据错乱以字节为单位逐字节拷贝不识别 int、char、结构体等数据类型通用性强内部无地址判断、容错校验逻辑执行开销小、拷贝速度快2.4 适用场景仅适用于源内存与目标内存完全独立、无任何重叠的场景是无重叠场景下的最优选择。2.5 代码示例#include string.h #include stdio.h int main(void) { char buf1[10] 123456; char buf2[10] {0}; // 无重叠内存拷贝拷贝6个字节有效数据 memcpy(buf2, buf1, 6); printf(拷贝结果%s\r\n, buf2); return 0; }三、memmove 函数详解3.1 函数原型void *memmove(void *dest, const void *src, size_t n);函数参数、返回值类型与 memcpy 完全一致调用方式无区别。3.2 核心特性支持内存重叠与非重叠全场景拷贝无论内存是否重叠均可保证数据拷贝准确无误安全性极高内部内置内存地址判断逻辑自动适配正向、反向两种拷贝方式相较于 memcpy 多了地址判断逻辑执行开销略大拷贝速度稍慢3.3 重叠内存拷贝逻辑memmove 会通过对比目标地址与源地址的高低自动切换拷贝方式彻底规避数据覆盖问题目标地址 源地址采用正向顺序拷贝从内存低地址向高地址逐字节搬运目标地址 源地址采用反向倒序拷贝从内存末尾向起始地址搬运避免未拷贝数据被提前覆盖3.4 适用场景适用于内存存在重叠、不确定内存是否重叠的场景常见于数组内部数据移位、缓冲区原地数据搬运等操作。3.5 内存重叠拷贝示例#include string.h #include stdio.h int main(void) { char arr[10] abcdef; // 自身内存重叠拷贝将前3个字节数据拷贝到数组下标2的位置 memmove(arr 2, arr, 3); printf(重叠拷贝结果%s\r\n, arr); // 输出结果ababcdef return 0; }四、memcpy 与 memmove 核心对比对比特性memcpymemmove内存重叠兼容性不支持重叠拷贝结果错乱完全支持全场景拷贝安全执行效率高无多余判断开销略低需做地址逻辑判断内部实现逻辑单纯正向逐字节拷贝地址判定 正向/反向双向拷贝适用范围仅限无重叠内存场景所有内存拷贝场景通用性强五、嵌入式开发高频易错点5.1 内存重叠误用这是嵌入式开发最常见的问题。当源内存与目标内存存在重叠时使用 memcpy 会覆盖未拷贝的原始数据导致数据错乱、功能异常严重时引发系统崩溃。内存不确定是否重叠时优先使用 memmove。5.2 拷贝长度越界拷贝字节数 n 不得超过源内存、目标内存的实际申请空间。越界拷贝会造成内存踩踏篡改其他变量、堆栈数据引发程序跑飞、死机、硬件异常等问题。5.3 缺失空指针校验嵌入式裸机、RTOS 开发中无系统内存保护机制。若 src 或 dest 为空指针直接调用拷贝函数会触发硬件异常、程序卡死调用前必须做空指针判断。5.4 结构体直接拷贝误区两个完全相同类型的结构体可直接通过内存拷贝完成整体赋值效率高于逐成员赋值。但需注意含指针成员的结构体不建议直接整体拷贝会出现浅拷贝问题导致数据异常。// 常规结构体安全拷贝示例 typedef struct { int age; char name[10]; } Stu_t; Stu_t stu_a {18, Zhang}; Stu_t stu_b {0}; // 整体结构体拷贝 memcpy(stu_b, stu_a, sizeof(Stu_t));5.5 非法内存拷贝禁止拷贝数组、变量申请空间以外的非法内存该部分内存数据随机且不受管控极易引发未知异常。六、底层手写实现助理解原理6.1 简易版 memcpy 实现纯正向逐字节拷贝无重叠处理还原原生 memcpy 核心逻辑void my_memcpy(void *dst, const void *src, size_t len) { // 强制转为字节指针按字节拷贝 char *d (char*)dst; const char *s (const char*)src; while(len--) { *d *s; } }6.2 安全版 memmove 实现增加地址判断兼容重叠与非重叠所有场景还原原生 memmove 安全逻辑void my_memmove(void *dst, const void *src, size_t len) { char *d (char*)dst; const char *s (const char*)src; // 目标地址在源地址前正向拷贝 if(d s) { while(len--) { *d *s; } } // 目标地址在源地址后反向拷贝避免数据覆盖 else { while(len--) { *(d len) *(s len); } } }七、嵌入式同类内存操作API 拓展详解在嵌入式 C 开发中除了 memcpy、memmove还有memset、memcmp、memccpy、strcpy/strncpy等高频内存/数据拷贝 API均为底层数据操作核心函数。很多新手容易混淆其适用场景本节统一对比讲解适配嵌入式开发规范。7.1 memset 内存初始化函数函数原型void *memset(void *s, int c, size_t n);核心功能将指定内存区域的每个字节统一赋值为参数 c仅低8位生效多用于内存清零、缓冲区初始化。嵌入式特性与易错点按字节赋值只能清零/置0xFF无法直接给 int 类型数组赋值 1、2 等非0值嵌入式缓冲区、结构体、数组初始化必备函数杜绝脏数据。示例代码char buf[32]; memset(buf, 0x00, sizeof(buf)); // 缓冲区整体清零7.2 memcmp 内存比较函数函数原型int memcmp(const void *s1, const void *s2, size_t n);核心功能逐字节对比两段内存数据不区分数据类型常用于校验拷贝结果、校验外设接收数据。返回值规则返回 0前 n 字节内存数据完全一致返回非0存在数据差异第一段大于/小于第二段。7.3 memccpy 安全截断拷贝函数函数原型void *memccpy(void *dest, const void *src, int c, size_t n);核心功能进阶版内存拷贝在拷贝 n 字节的同时检测是否出现指定字符 c遇到 c 则立即停止拷贝自动截断适合带结束标识的缓冲区拷贝。适用场景串口、CAN 等不定长报文拷贝自动识别报文结束符避免多余拷贝。7.4 strcpy / strncpy 字符串专属拷贝函数核心区别与memcpymemcpy 是纯内存二进制拷贝不识别结束符str 系列是字符串拷贝依赖\0结束符仅适用于字符串。1、strcpy自动识别\0结束拷贝无长度限制极易造成内存越界嵌入式工程禁止使用。2、strncpy限定最大拷贝长度 n规避越界风险但不会自动补 \0使用后需手动补结束符避免字符串乱码。八、所有内存拷贝 API 终极对比嵌入式专用API函数是否支持重叠是否按字节是否识别结束符嵌入式推荐场景memcpy不支持是否无重叠、追求高效率二进制拷贝memmove支持是否不确定重叠、缓冲区原地移位memset—是否内存清零、缓冲区初始化memcmp—是否内存数据校验、报文比对memccpy不支持是是不定长报文、带结束符数据拷贝strncpy不支持是是专用字符串安全拷贝九、嵌入式开发使用总结明确无内存重叠优先使用 memcpy最大化拷贝效率适配常规数据复制场景内存未知/存在重叠统一使用 memmove牺牲微小效率换取程序稳定性规避数据异常裸机开发必须添加空指针校验、长度边界校验杜绝硬件异常与内存踩踏数组、缓冲区、普通结构体批量数据搬运优先使用标准内存拷贝函数代码简洁且执行效率高二进制数据一律用 mem 系列函数禁止使用 str 系列避免截断、乱码问题初始化内存强制使用 memset字符串安全拷贝统一使用 strncpy废弃 strcpy。明确无内存重叠优先使用 memcpy最大化拷贝效率适配常规数据复制场景内存未知/存在重叠统一使用 memmove牺牲微小效率换取程序稳定性规避数据异常裸机开发必须添加空指针校验、长度边界校验杜绝硬件异常与内存踩踏数组、缓冲区、普通结构体批量数据搬运优先使用标准内存拷贝函数代码简洁且执行效率高。