当前位置: 首页 > news >正文

【54】结构体:结构体指针的内存与通信

【54】结构体:结构体指针的内存与通信


七律 · 结构体指针

指针寻址破边界,结构传输显神通
函数入口化繁简,成员访问箭头通
字节打包还原易,跨片通信一脉承
内存布局细解析,工程规范护始终


引言

结构体指针是嵌入式开发中高效管理复杂数据的关键工具。本文详细解析结构体指针的两个核心用途——数据传输与函数参数传递,并通过代码示例展示其内存布局、访问方式及实际应用,帮助开发者掌握结构体指针的底层原理与工程实践。

摘要

结构体指针通过直接操作内存地址,实现结构体数据的高效传输与函数参数传递。本文结合STC8单片机开发场景,提供内存布局分析、通信示例及函数参数传递方案,确保代码可读性与可维护性。

关键词

结构体指针、内存布局、函数参数、数据传输、箭头操作符


硬件设计

开发环境

  • 单片机型号:STC8H1K08(8位51内核,8KB Flash,512B RAM)
  • 外设配置:UART0用于调试输出,波特率115200
  • 电路连接
    graph LR  
      A[STC8H1K08 UART0] --> B[USB转TTL模块(CH340)]  
      B --> C[电脑串口助手(如XCOM)]  
    

软件配置

模块化架构

  1. BSP层bsp_uart.c实现UART通信
  2. 驱动层drv_struct.c封装结构体操作函数
  3. 应用层main.c演示指针用法

代码实现

1. 结构体指针基础

结构体定义与指针声明
// drv_struct.h  
typedef struct {  
    uint8_t u8Data_A;    // 1字节  
    uint32_t u32Data_B;  // 4字节  
} StructMould_t;  

extern StructMould_t g_StructInstance; // 结构体变量  
extern StructMould_t* pStructPtr;      // 结构体指针  
内存布局分析
  • 结构体变量g_StructInstance占用5字节(1+4)。
  • 指针变量pStructPtr在8位单片机中占3字节(地址存储需求)。
// 内存布局示例  
Address | Data Type       | Size (B)  
0x00    | g_StructInstance.u8Data_A | 1  
0x01    | g_StructInstance.u32Data_B | 4  
Total: 5 bytes  
成员访问方式对比
// 成员调用(直接访问)  
g_StructInstance.u8Data_A = 5;  

// 指针调用(通过地址访问)  
pStructPtr = &g_StructInstance;  
pStructPtr->u8Data_A += 5; // 等价于 *(pStructPtr->u8Data_A) +=5  

2. 结构体指针的两个核心用途

用途1:数据传输与还原
// 将结构体转换为字节数组(发送)  
void struct_to_array(uint8_t* pBuffer) {  
    memcpy(pBuffer, &g_StructInstance, sizeof(g_StructInstance));  
}  

// 从字节数组还原结构体(接收)  
void array_to_struct(uint8_t* pBuffer) {  
    memcpy(&g_StructInstance, pBuffer, sizeof(g_StructInstance));  
}  
用途2:函数参数传递
// 函数原型:通过指针传递结构体  
void process_struct(StructMould_t* pStruct) {  
    pStruct->u32Data_B = pStruct->u8Data_A * 1000;  
}  

// 调用示例  
process_struct(&g_StructInstance);  

3. 内存占用与指针类型

指针大小规则
  • 8位单片机:所有指针占3字节(地址范围0~16MB)。
  • 32位单片机:指针占4字节(支持更大地址空间)。
// 内存占用验证  
void memory_check() {  
    bsp_uart_send_ulong(sizeof(g_StructInstance)); // 输出5  
    bsp_uart_send_ulong(sizeof(pStructPtr));        // 输出3  
}  

测试验证

验证步骤

  1. 编译检查:确保无警告,指针类型与结构体匹配。

  2. 内存观察

    void test_pointer() {  
        g_StructInstance.u8Data_A = 5;  
        pStructPtr = &g_StructInstance;  
        pStructPtr->u8Data_A += 5; // 最终值为10  
    
        bsp_uart_send_ulong(g_StructInstance.u8Data_A); // 输出10  
    }  
    
  3. 数据传输测试

    uint8_t buffer[5];  
    struct_to_array(buffer); // 将结构体数据存入buffer  
    array_to_struct(buffer); // 从buffer还原结构体  
    

扩展应用

1. 跨片通信场景

// 发送端:将结构体打包发送  
void send_struct() {  
    uint8_t tx_buffer[sizeof(StructMould_t)];  
    struct_to_array(tx_buffer);  
    uart_send(tx_buffer, sizeof(tx_buffer));  
}  

// 接收端:从字节数组还原结构体  
void recv_struct(uint8_t* rx_buffer) {  
    array_to_struct(rx_buffer);  
}  

2. 函数参数优化

// 传统方式(参数过多)  
void process_old(uint8_t data_a, uint32_t data_b) {  
    // 复杂逻辑  
}  

// 优化方式(指针传递)  
void process_new(StructMould_t* pStruct) {  
    // 直接访问pStruct->u8Data_A等成员  
}  

总结

结构体指针通过直接操作内存地址,实现数据高效传输与函数参数传递。其核心优势在于:

  1. 数据打包与还原:通过memcpy快速转换结构体与字节数组,适用于通信场景。
  2. 函数参数简化:用单个指针替代多个参数,提升代码可读性与可维护性。
  3. 内存布局清晰:通过sizeof和指针操作符(.->)精准控制数据访问。

注意

  1. 全局变量以g_前缀命名,指针以p前缀命名(如pStructPtr),符合嵌入式代码规范。
  2. 内存操作需确保目标缓冲区大小足够,避免溢出。
  3. 跨片通信时需处理字节序(Big-Endian/Little-Endian),本文假设双方使用相同字节序。

相关文章:

  • Qt信号槽
  • 3D设计在UI中的应用:2025年的设计新潮流!
  • OpenMCU(五):STM32F103时钟树初始化分析
  • 黑帽SEO之搜索引擎劫持-域名劫持原理分析
  • 银发浪潮下的智能护理革命:全球老龄化社会护理机器人发展研究
  • AI时代新坐标!火石会:应时而生,聚势而为
  • AI推理胜过人脑?思维模型!【34】长线思考思维模型
  • 普冉单片机PY32F002BF,使用adc内部参考电压VREFINT检测。
  • uniapp 微信小程序项目中 地图 map组件 滑动面板
  • 2025 年广东水利水电安全员考试:理论与实践融合攻略​
  • 通过redis缓存获取菜品数据
  • Docker学习--容器操作相关命令--docker events 命令
  • 【mapreduce】工作原理
  • livekit ICE连接失败的一些总结
  • 鬼泣:升龙系统
  • Linux-线程概念与线程控制的常用操作
  • 通过动态获取项目的上下文路径来确保请求的 URL 兼容两种启动方式(IDEA 启动和 Tomcat 部署)下都能正确解析
  • 深度解析算法之滑动窗口
  • 清晰易懂的Rust安装与配置教程
  • 【区块链安全 | 第十五篇】类型之值类型(二)
  • 快速建手机网站/超级外链工具源码
  • 国土资源网站建设方案/长沙网络公关公司
  • 做推广网站公司/免费域名怎么注册
  • java做网站建设后台/品牌营销策划机构
  • 网站开发包括几个部分/个人网站注册平台
  • 太原网站建设托管/网站开发平台有哪些