news 2026/5/15 7:55:33

memcpy深度解析:`resistance` vs `resistance` 关键区别

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
memcpy深度解析:`resistance` vs `resistance` 关键区别

memcpy深度解析:&resistancevsresistance关键区别

一、本质区别:目标地址的不同含义

1. 内存操作示意图

graph LR
S[源数据] -->|memcpy| D[目标地址]

subgraph 场景1:memcpy(&resistance, …)
A[resistance变量] -->|&resistance 取地址| D1[变量内存位置]
end

subgraph 场景2:memcpy(resistance, …)
B[resistance指针] -->|resistance 指针值| D2[指针指向的内存区域]
end

2. 核心区别对比表

特性memcpy(&resistance, src, size)memcpy(resistance, src, size)
目标类型变量地址指针变量
操作对象resistance变量本身resistance指针指向的内存区域
内存影响直接修改resistance的值修改resistance指向的数据
典型用途填充局部/全局变量填充动态分配的内存
风险变量大小不足导致溢出指针未初始化导致崩溃

二、代码实例深度分析

1. 变量类型定义示例

// 情况1:resistance是普通变量uint32_tresistance;// 4字节变量// 情况2:resistance是指针uint32_t*resistance;// 指向uint32_t的指针

2. 正确用法示例

// 示例1:使用&操作符(resistance是变量)uint32_tresistance;// 声明一个4字节变量memcpy(&resistance,&usRegHoldingBuf[res_reg],4);// 正确:将4字节数据复制到resistance变量// 示例2:直接使用指针(resistance是指针)uint32_t*resistance=malloc(sizeof(uint32_t));// 分配内存memcpy(resistance,&usRegHoldingBuf[res_reg],4);// 正确:将数据复制到指针指向的内存区域

3. 错误用法及后果

// 错误示例1:变量误用为指针uint32_tresistance;memcpy(resistance,&usRegHoldingBuf[res_reg],4);// 崩溃!将变量值当作地址访问(resistance包含随机值)// 错误示例2:指针未初始化uint32_t*resistance;// 未初始化memcpy(resistance,&usRegHoldingBuf[res_reg],4);// 崩溃!访问随机内存地址(野指针)// 错误示例3:大小不匹配floatresistance;// 4字节但类型不同memcpy(&resistance,&usRegHoldingBuf[res_reg],4);// 危险!按字节复制可能破坏浮点表示

三、内存布局详解

1. 正确情况内存布局

Modbus寄存器

栈内存

&resistance

memcpy操作

resistance变量

0x1000

usRegHoldingBuf

0x2000-0x2003

复制4字节数据

2. 错误情况内存布局

Modbus寄存器

memcpy操作

栈内存

值=0xDEADBEEF

resistance变量

0x1000

usRegHoldingBuf

0x2000-0x2003

0xDEADBEEF

尝试写入

四、实战应用场景

1. Modbus数据处理(推荐方案)

// 安全读取32位寄存器值uint32_tread_modbus_register(uint16_treg_index){uint32_tvalue;// 检查寄存器范围if(reg_index>=MAX_REGISTERS-3){return0;// 错误处理}// 使用memcpy避免字节序问题memcpy(&value,&usRegHoldingBuf[reg_index],4);returnntohl(value);// 转换字节序}

2. 动态数据处理

// 创建寄存器数据副本uint32_t*create_register_copy(uint16_tstart,uint16_tcount){size_tsize=count*sizeof(uint16_t);uint32_t*buffer=malloc(size);if(!buffer)returnNULL;// 直接使用指针复制数据memcpy(buffer,&usRegHoldingBuf[start],size);returnbuffer;}

五、常见问题解决方案

1. 类型安全增强

// 类型安全的memcpy封装template<typename T>voidsafe_memcpy(T&dest,constvoid*src){static_assert(!std::is_pointer<T>::value,"Use pointer version for pointer types");memcpy(&dest,src,sizeof(T));}// 指针版本重载template<typename T>voidsafe_memcpy(T*dest,constvoid*src,size_tcount=1){memcpy(dest,src,count*sizeof(T));}// 使用示例uint32_tresistance;safe_memcpy(resistance,&usRegHoldingBuf[res_reg]);// 自动推断大小uint32_t*pRes=malloc(sizeof(uint32_t));safe_memcpy(pRes,&usRegHoldingBuf[res_reg]);// 指针版本

2. 字节序处理

// 处理大端序存储的寄存器数据uint32_tread_big_endian(constuint16_t*reg_ptr){uint32_tresult;uint8_t*bytes=(uint8_t*)&result;// 手动处理字节序bytes[0]=(reg_ptr[0]>>8)&0xFF;bytes[1]=reg_ptr[0]&0xFF;bytes[2]=(reg_ptr[1]>>8)&0xFF;bytes[3]=reg_ptr[1]&0xFF;returnresult;}// 使用memcpy的优化版本uint32_tread_big_endian_optimized(constuint16_t*reg_ptr){union{uint32_tvalue;uint16_twords[2];}converter;memcpy(converter.words,reg_ptr,4);return(converter.words[0]<<16)|converter.words[1];}

3. 边界检查强化

// 带边界检查的安全复制boolsafe_register_copy(void*dest,size_tdest_size,uint16_treg_index,size_tcopy_size){// 检查源边界if(reg_index+(copy_size/2)>MAX_REGISTERS){returnfalse;}// 检查目标大小if(dest_size<copy_size){returnfalse;}memcpy(dest,&usRegHoldingBuf[reg_index],copy_size);returntrue;}

六、调试技巧与验证方法

1. 内存断点设置

// GDB调试示例(gdb)p&resistance// 查看变量地址$1=(uint32_t*)0x7fffffffdcbc(gdb)watch*(uint32_t*)0x7fffffffdcbc// 设置内存写入断点Hardware watchpoint2:*(uint32_t*)0x7fffffffdcbc(gdb)p resistance// 查看指针值$2=(uint32_t*)0x5555555592a0(gdb)watch*(uint32_t*)0x5555555592a0// 设置指针指向内存的断点

2. 运行时检测

// 添加调试检查#defineDEBUG_MEMCPY(dest,src,size)do{\printf("memcpy: %p -> %p, size=%zu\n",src,dest,size);\if(((uintptr_t)dest<0x1000)||((uintptr_t)src<0x1000)){\printf("ERROR: Invalid memory access!\n");\abort();\}\memcpy(dest,src,size);\}while(0)// 使用示例DEBUG_MEMCPY(&resistance,&usRegHoldingBuf[res_reg],4);

七、最佳实践总结

1. 选择指南

普通变量

指针变量

数组

需要复制数据

目标是什么类型?

使用 & 取地址符

直接使用指针

使用数组名

确保变量大小足够

确保指针已初始化

确保不越界

2. 黄金法则

  1. 地址操作符规则
  • 对普通变量使用&
  • 对指针变量直接使用
  • 对数组使用数组名(等效于指针)
  1. 安全检查清单
if(使用指针){确保指针已初始化();确保指针指向的内存有效();}else{确保目标变量大小足够();}确保源数据可访问();确保复制大小正确();
  1. 防御性编程
// 安全复制模板voidsafe_register_copy(void*dest,uint16_t*src,size_tsize){assert(dest!=NULL);assert(src!=NULL);assert((src>=usRegHoldingBuf)&&(src+size/2<=usRegHoldingBuf+MAX_REGISTERS));memcpy(dest,src,size);}

3. 最终结论

在您的代码中:

memcpy(&resistance,&usRegHoldingBuf[res_reg],4);

这是正确用法,前提是:

  1. resistanceuint32_t或其它4字节类型的变量
  2. res_reg在寄存器数组的有效范围内

而:

memcpy(resistance,&usRegHoldingBuf[res_reg],4);

需要

  1. resistance是指向足够内存的指针
  2. 指针已正确初始化(如resistance = malloc(4);

关键记忆点
&resistance→ 我要修改resistance变量本身
resistance→ 我要修改resistance指向的内容
选错目标地址会导致严重内存错误!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/13 23:20:28

通过postman工具测试一个https post请求

Qwen3-Max 使用 Postman 测试一个 HTTPS POST 请求非常简单,以下是详细步骤: ✅ 前提条件 已安装 Postman 你有目标接口的 URL(例如:https://api.example.com/v1/login) 你知道请求需要的数据格式(如 JSON、表单等)和所需字段 📌 步骤详解 1. 打开 Postman 启动 Po…

作者头像 李华
网站建设 2026/5/8 10:09:10

【网络安全】从入门到顶尖 网络安全行业发展路径指南

文章目录 网络安全行业发展路径与成就达成指南一、行业趋势与核心方向二、发展路径规划 1. 小白入门阶段&#xff08;0-2年&#xff09;2. 进阶高手阶段&#xff08;3-5年&#xff09;3. 成就突破阶段&#xff08;5-10年&#xff09; 三、批判性建议与风险警示四、终极目标达成…

作者头像 李华
网站建设 2026/5/10 7:28:42

微信小程序和HTML5有什么区别,如何互相内嵌使用?

目录 一、微信小程序介绍二、什么是内嵌H5页面三、小程序内嵌H5页面的如何交互四、微信小程序的应用场景 一、微信小程序介绍 微信小程序是一种基于微信平台的轻量级应用&#xff0c;它无需下载安装&#xff0c;用户只需通过微信扫一扫或搜索即可快速打开使用。与传统的APP相比…

作者头像 李华
网站建设 2026/5/13 3:48:25

计算机毕设java迎新网管理系统 基于Java的高校新生报到信息化管理系统设计与实现 Java技术驱动的高校迎新管理平台开发与应用

计算机毕设java迎新网管理系统y1s2o9&#xff08;配套有源码 程序 mysql数据库 论文&#xff09; 本套源码可以在文本联xi,先看具体系统功能演示视频领取&#xff0c;可分享源码参考。 随着高校招生规模的不断扩大&#xff0c;新生报到管理成为高校开学季的重要工作之一。传统…

作者头像 李华
网站建设 2026/5/10 22:48:46

【小程序毕设源码分享】基于springboot+小程序的景区的智慧导游小程序的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华