一、结构体指针是什么?
结构体指针是一个指向结构体变量的指针变量,它存储的是结构体变量的内存地址。通过结构体指针,我们可以直接访问结构体的成员,而不需要拷贝整个结构体,大大节省了内存空间。
二、核心语法规则
- 普通结构体变量 :使用
.(点号)访问成员,例如dev.temp。 - 结构体指针 :使用
->(箭头)访问成员,例如p_dev->temp。 - 绑定地址 :定义结构体指针后,必须绑定一个已存在的结构体变量的地址(使用
&取地址符),否则会导致程序跑飞。
三、基础代码示例:理解结构体指针
我们先看一个最基础的示例,直观感受结构体指针的使用:
c
#include <stdio.h>
// 定义设备结构体
struct Device
{
int temp; // 温度
int fan_speed; // 风扇档位
};
int main(void)
{
// 定义结构体变量并初始化
struct Device dev = {28, 2};
// 定义结构体指针,绑定dev的地址
struct Device *p_dev = &dev;
// 通过指针访问成员
printf("温度:%d℃\n", p_dev->temp);
printf("风扇档位:%d\n", p_dev->fan_speed);
return 0;
}
运行结果:
plaintext
温度:28℃
风扇档位:2
四、结构体指针的核心优势
- 节省内存:传递结构体时,只需要传递指针(4字节),而不需要拷贝整个结构体,避免了内存浪费。
- 高效访问:直接通过指针访问结构体成员,不需要拷贝数据,访问速度更快。
- 代码简洁:在大型工程中,使用结构体指针可以简化函数参数传递,让代码更易维护。
五、嵌入式实战场景:STM32外设寄存器访问
在STM32开发中,外设寄存器通常以结构体的形式定义,通过结构体指针可以直接访问寄存器,这是STM32库的核心设计思想。
示例:访问GPIO外设寄存器
c
#include "stm32f10x.h"
// 假设我们要访问GPIOC的ODR寄存器
void GPIO_Toggle(void)
{
// 定义GPIO_TypeDef类型的指针,指向GPIOC的基地址
GPIO_TypeDef *p_gpio = GPIOC;
// 通过指针访问ODR寄存器,翻转第13位(LED灯)
p_gpio->ODR ^= (1 << 13);
}
在STM32的标准库中,GPIO_TypeDef是一个结构体,包含了GPIO的所有寄存器,GPIOC是这个结构体的基地址,通过指针可以直接访问各个寄存器。
六、实战场景:传感器数据访问
在传感器驱动开发中,传感器的数据通常以结构体的形式存储,通过结构体指针可以高效地访问传感器数据。
示例:DHT11温湿度传感器数据访问
c
#include <stdio.h>
// 定义DHT11传感器数据结构体
typedef struct {
float temperature; // 温度
float humidity; // 湿度
uint8_t check_sum; // 校验和
} DHT11_Data;
// 定义传感器驱动函数,返回结构体指针
DHT11_Data *DHT11_ReadData(void)
{
static DHT11_Data data; // 静态变量,避免函数返回后数据丢失
// 模拟读取传感器数据
data.temperature = 25.5;
data.humidity = 60.0;
data.check_sum = (uint8_t)(data.temperature + data.humidity);
return &data;
}
int main(void)
{
// 调用驱动函数,获取传感器数据指针
DHT11_Data *p_sensor = DHT11_ReadData();
// 通过指针访问传感器数据
printf("温度:%.1f℃\n", p_sensor->temperature);
printf("湿度:%.1f%%\n", p_sensor->humidity);
return 0;
}
七、实战场景:设备参数缓存
在嵌入式系统中,设备参数通常存储在结构体中,通过结构体指针可以高效地访问和修改参数。
示例:设备参数管理
c
#include <stdio.h>
#include <string.h>
// 定义设备参数结构体
typedef struct {
char device_name[20]; // 设备名称
int baud_rate; // 波特率
int power_mode; // 电源模式
uint8_t is_connected; // 连接状态
} Device_Params;
// 初始化设备参数
void Device_Init(Device_Params *p_params)
{
strcpy(p_params->device_name, "SmartDevice");
p_params->baud_rate = 115200;
p_params->power_mode = 1;
p_params->is_connected = 0;
}
int main(void)
{
Device_Params params;
Device_Init(¶ms); // 传递结构体指针
// 通过指针访问参数
printf("设备名称:%s\n", params.device_name);
printf("波特率:%d\n", params.baud_rate);
return 0;
}
八、使用结构体指针的注意事项
- 必须绑定地址:定义结构体指针后,必须绑定一个已存在的结构体变量的地址,否则会导致程序跑飞。
- 避免野指针 :不要使用未初始化的指针,不要返回局部变量的指针(除非使用
static修饰)。 - 字节对齐:结构体的大小可能会因为字节对齐而变大,在使用指针访问时要注意成员的偏移量。
九、总结
结构体指针是嵌入式C语言中非常实用的技巧,它能帮你在STM32外设访问、传感器数据处理、设备参数管理等场景中,高效地访问结构体成员,节省内存空间,简化代码逻辑。在大型工程中,结构体指针几乎是必备的技巧,掌握它能让你的嵌入式开发能力更上一层楼。
如果你觉得这篇文章对你有帮助,欢迎点赞收藏,也可以在评论区分享你使用结构体指针的实战经验!