在ARM嵌入式开发中,C++函数的参数传递方式会直接影响程序的执行效率和内存使用情况,引用传递和指针传递是两种最常用的参数传递形式,二者在语法特性和适用场景上存在明显差异,开发者需要根据实际需求合理选择。

引用传递的基本特性与应用
引用传递是C++特有的参数传递方式,本质是给已存在的变量起一个别名,传递过程中不会创建新的变量副本,因此不会产生额外的内存开销。引用必须在定义时初始化,且后续无法再绑定到其他变量,这一特性让引用传递的安全性更高。
在ARM嵌入式开发中,引用传递适合以下场景:
- 传递小型结构体或类对象,避免值传递带来的拷贝开销,节省嵌入式设备有限的内存资源
- 需要修改函数外部变量的值,且不需要进行空值判断的场景
- 作为函数返回值,返回外部变量的引用,减少返回时的拷贝操作
下面是一段引用传递的实际应用代码示例,实现嵌入式设备传感器数据的读取与修改:
#include <stdint.h>
// 定义传感器数据结构体
typedef struct {
uint16_t temperature; // 温度值,单位0.1℃
uint16_t humidity; // 湿度值,单位0.1%
} SensorData;
// 引用传递修改传感器数据
void updateSensorData(SensorData &data) {
// 模拟读取传感器原始数据
uint16_t raw_temp = 250; // 原始温度值25.0℃
uint16_t raw_humi = 600; // 原始湿度值60.0%
data.temperature = raw_temp;
data.humidity = raw_humi;
}
// 引用传递返回计算结果
const uint16_t &getTemperature(const SensorData &data) {
return data.temperature;
}
int main() {
SensorData sensor_data;
updateSensorData(sensor_data); // 传递引用,修改外部结构体
uint16_t temp = getTemperature(sensor_data); // 获取温度值
while(1) {
// 嵌入式主循环逻辑
}
return 0;
}
指针传递的基本特性与应用
指针传递传递的是变量的内存地址,通过解引用操作可以访问或修改对应地址的内容。指针可以指向任意同类型的变量,也支持赋值为空指针,灵活性比引用更高。不过指针传递需要注意空指针判断,否则可能出现非法内存访问的问题。
在ARM嵌入式开发中,指针传递的适用场景包括:
- 访问硬件寄存器,ARM嵌入式开发中硬件寄存器通常映射到固定的内存地址,需要通过指针操作这些地址
- 传递数组或批量数据,通过指针偏移可以高效遍历数据,适合传感器批量数据读取、通信数据解析等场景
- 需要支持空值判断的场景,比如可选参数的传递,当指针为空时表示不需要处理对应参数
- 动态内存管理场景,嵌入式开发中如果需要动态申请内存,需要通过指针操作申请到的内存空间
下面是指针传递操作硬件寄存器的代码示例,以STM32系列MCU的GPIO寄存器操作为例:
#include <stdint.h>
// 定义GPIO寄存器结构体,对应STM32 GPIO寄存器映射
typedef struct {
volatile uint32_t MODER; // 模式寄存器
volatile uint32_t OTYPER; // 输出类型寄存器
volatile uint32_t OSPEEDR; // 输出速度寄存器
volatile uint32_t PUPDR; // 上拉下拉寄存器
volatile uint32_t IDR; // 输入数据寄存器
volatile uint32_t ODR; // 输出数据寄存器
} GPIO_TypeDef;
// GPIO端口基地址定义
#define GPIOA_BASE 0x40020000
// 将基地址转换为GPIO结构体指针
#define GPIOA ((GPIO_TypeDef *)GPIOA_BASE)
// 指针传递配置GPIO引脚为输出模式
void gpio_pin_config(GPIO_TypeDef *gpio, uint8_t pin) {
if(gpio == 0) { // 空指针判断,避免非法访问
return;
}
// 清除对应引脚的模式位
gpio->MODER &= ~(0x3 << (pin * 2));
// 设置为通用输出模式
gpio->MODER |= (0x1 << (pin * 2));
}
// 指针传递设置GPIO引脚输出电平
void gpio_pin_set(GPIO_TypeDef *gpio, uint8_t pin, uint8_t level) {
if(gpio == 0) {
return;
}
if(level) {
gpio->ODR |= (1 << pin); // 输出高电平
} else {
gpio->ODR &= ~(1 << pin); // 输出低电平
}
}
int main() {
gpio_pin_config(GPIOA, 5); // 配置PA5引脚为输出
while(1) {
gpio_pin_set(GPIOA, 5, 1); // PA5输出高电平
// 延时逻辑
gpio_pin_set(GPIOA, 5, 0); // PA5输出低电平
// 延时逻辑
}
return 0;
}
两种传递方式的选择建议
在ARM嵌入式开发中,选择引用还是指针传递可以参考以下原则:
| 对比维度 | 引用传递 | 指针传递 | |
|---|---|---|---|
| 内存开销 | 无额外开销,本质是别名 | 无额外开销,传递地址值 | |
| 空值支持 | 不支持,必须初始化绑定变量 | 支持,可传递空指针 | |
| 适用场景 | 小型对象传递、必须修改外部变量的场景 | 硬件寄存器操作、数组处理、可选参数场景 | |
| 安全性 | 更高,不存在空引用问题 | 较低,需要手动判断空指针 |
如果不需要操作空值,且传递的是需要修改的外部变量或小型对象,优先选择引用传递,语法更简洁,安全性更高。如果需要操作硬件寄存器、处理数组批量数据或者需要支持可选参数,优先选择指针传递,灵活性更能满足需求。
注意事项
在ARM嵌入式开发中使用两种传递方式时,还需要注意以下问题:
- 引用传递不要返回局部变量的引用,局部变量在函数结束后会被释放,返回其引用会导致非法访问
- 指针传递操作硬件寄存器时,要确保指针指向的地址是合法的寄存器映射地址,避免访问未定义的地址空间
- 嵌入式开发中内存资源有限,尽量避免使用指针进行复杂的动态内存操作,防止内存泄漏和碎片问题
- 如果传递的是只读参数,建议给引用或指针添加
const修饰,明确参数不会被修改,提升代码的可读性和安全性
ARM嵌入式开发中C++的参数传递选择需要结合具体场景,合理运用引用和指针传递,才能在保证程序正确性的前提下,最大化提升程序的运行效率,适配嵌入式设备的资源限制。