【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),本文假设双方使用相同字节序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值