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

C/C++ 结构体:. 与 -> 的区别与用法及其STM32中的使用

目录

  • 引言

  • 一、深入理解 C/C++ 结构体:.-> 的区别与用法

    • 1. .(点运算符)详解
    • 2. ->(箭头运算符)详解
    • 3. .-> 的等价与转换
    • 4. 常见错误与调试技巧
    • 5. C++ 特性与运算符重载
    • 6. 实战案例:链表与智能指针
    • 7. 最佳实践与性能考量
  • 二、在 STM32 单片机中,结构体的 .-> 使用详解

    • 1. 外设寄存器访问:-> 的绝对主场
    • 2. 库函数配置:.-> 的混合使用
    • 3. 动态分配与回调:-> 的灵活应用
    • 4. 常见错误与避坑指南
    • 5. 实战技巧与性能优化
  • 三、综合总结


引言

结构体(struct)在 C/C++ 及嵌入式开发中广泛应用。访问结构体成员时,使用点运算符(.)或箭头运算符(->)是基础操作。本文分为两大部分:

  1. 深入理解 C/C++ 结构体:讲解 .-> 的原理与用法,包括调试与最佳实践。
  2. 在 STM32 单片机中应用:结合外设寄存器、HAL 库及动态句柄场景,分享嵌入式开发中的实战示例与优化技巧。

一、深入理解 C/C++ 结构体:.-> 的区别与用法

1. .(点运算符)详解

作用:用于直接访问结构体变量的成员。

示例代码

#include <stdio.h>
#include <string.h>struct Student {char name[50];int age;float score;
};int main() {struct Student stu1;  // 定义结构体变量strcpy(stu1.name, "Alice");  // 使用 . 访问成员stu1.age = 20;stu1.score = 95.5;printf("Name: %s, Age: %d, Score: %.1f\n", stu1.name, stu1.age, stu1.score);return 0;
}

关键点

  • stu1 是一个结构体变量,使用 . 访问其成员。

2. ->(箭头运算符)详解

作用:用于访问结构体指针所指向的对象的成员。

示例代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>struct Student {char name[50];int age;float score;
};int main() {struct Student *stu_ptr = malloc(sizeof(struct Student));  // 动态分配内存strcpy(stu_ptr->name, "Bob");  // 使用 -> 访问指针指向的成员stu_ptr->age = 22;stu_ptr->score = 88.5;printf("Name: %s, Age: %d, Score: %.1f\n", stu_ptr->name, stu_ptr->age, stu_ptr->score);free(stu_ptr);  // 释放内存return 0;
}

关键点

  • stu_ptr 是一个结构体指针,使用 -> 访问其指向的结构体成员。
  • -> 等同于 (*ptr).member 的简写。

3. .-> 的等价与转换

struct Student *ps = &stu1;
// 等价示例:
ps->age = 25;      // 使用 ->
(*ps).age = 25;    // 解引用后用 .

链式访问时,-> 更简洁:

node->next->data;

4. 常见错误与调试技巧

场景错误示例正确写法调试思路
对指针使用 .stu_ptr.name = 20;stu_ptr->name = 20;检查变量类型
对实例使用 ->stu1->age = 20;stu1.age = 20;确认对象是否指针
空指针访问Node *n = NULL; n->x;添加空指针检查

调试技巧

  1. 使用 GDB:p stu1 vs p *stu_ptr
  2. 加断言:assert(ptr); ptr->field;
  3. 使用 Valgrind 检测内存问题

5. C++ 特性与运算符重载

  • 智能指针std::unique_ptr<T>std::shared_ptr<T> 支持 ->
  • 运算符重载:自定义 operator->() 实现代理模式。
struct Wrapper {Target* ptr;Target* operator->() { return ptr; }
};

6. 实战案例:链表与智能指针

6.1 传统 C 链表

struct Node { int data; struct Node *next; };

6.2 C++ 智能指针实现

#include <memory>
#include <iostream>struct Node { int data; std::unique_ptr<Node> next; };auto head = std::make_unique<Node>();
head->data = 1;
head->next = std::make_unique<Node>();
head->next->data = 2;

自动释放,无需手动 delete


7. 最佳实践与性能考量

  1. 优先使用智能指针与容器
  2. 注意结构体对齐与缓存友好
  3. 简化多级解引用为 p->next->x

二、在 STM32 单片机中,结构体的 .-> 使用详解

在 STM32 单片机开发中,结构体被广泛用于外设寄存器映射、HAL/LL 库配置及自定义数据管理。以下在不修改示例的基础上,保留原内容并优化说明。

1. 外设寄存器访问:-> 的绝对主场

// STM32F4 GPIO 寄存器定义
typedef struct {__IO uint32_t MODER;__IO uint32_t OTYPER;__IO uint32_t OSPEEDR;__IO uint32_t PUPDR;__IO uint32_t IDR;__IO uint32_t ODR;__IO uint32_t BSRR;__IO uint32_t LCKR;__IO uint32_t AFR[2];
} GPIO_TypeDef;#define GPIOA ((GPIO_TypeDef *)0x40020000U)// 设置 PA0 为推挽输出,高速,无上下拉
GPIOA->MODER  &= ~(3U << (0 * 2));
GPIOA->MODER  |=  (1U << (0 * 2));
GPIOA->OTYPER &= ~(1U << 0);
GPIOA->OSPEEDR |= (2U << (0 * 2));
GPIOA->PUPDR   &= ~(3U << (0 * 2));// 切换 PA0 电平
GPIOA->ODR ^= (1U << 0);

关键点

  • GPIOA 是指针宏,需用 ->
  • 可加 __DSB()/__ISB() 保证时序

2. 库函数配置:.-> 的混合使用

UART_HandleTypeDef huart2;
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
HAL_UART_Init(&huart2);
  • 配置结构体变量用 .
  • HAL 内部以 -> 操作寄存器

3. 动态分配与回调:-> 的灵活应用

DMA_HandleTypeDef *hdma = malloc(sizeof(DMA_HandleTypeDef));
hdma->Instance = DMA1_Channel1;
hdma->Init.Direction = DMA_MEMORY_TO_PERIPH;
HAL_DMA_Init(hdma);
void USART2_IRQHandler(void) {HAL_UART_IRQHandler(&huart2);
}
  • 建议 memset 清零并检查 NULL
  • 回调使用句柄指针,结合 HAL 生命周期管理

4. 常见错误与避坑指南

场景错误示例
变量误用 ->GPIO_InitStruct->Pin = ...;
指针未初始化访问hi2c->Instance = I2C1;

5. 实战技巧与性能优化

  • 位带别名提升 GPIO 操作速度
  • DMA 缓存一致性:使用 SCB_CleanDCache()
  • 多句柄存储于数组或链表

三、综合总结

  • 通用 C/C++ 场景

    • . 用于访问结构体实例成员,简洁直观
    • -> 用于解引用结构体指针并访问其成员,语法糖简化书写
  • STM32 嵌入式场景

    • . 用于配置 HAL/LL 库的局部结构体变量(InitStruct 等)
    • -> 用于外设寄存器映射(宏定义指针)、动态句柄和回调中访问成员
  • C++ 扩展

    • 智能指针(std::unique_ptr/std::shared_ptr)原生支持 ->,自动管理生命周期
    • 可自定义 operator-> 实现代理或链式访问
  • 性能与可靠性优化

    • 位掩码和位带操作加速单比特寄存器访问
    • DMA 传输需进行 Cache 管理(如 SCB_CleanDCache()SCB_InvalidateDCache()
    • 关注结构体对齐与数据局部性,提高缓存友好性

http://www.xdnf.cn/news/634807.html

相关文章:

  • 2025.5.25总结
  • Windows 11 [close recent file browsing history]
  • 对WireShark 中的UDP抓包数据进行解析
  • win11 禁用/恢复 内置笔记本键盘(保证管用)
  • 嵌入式软件--DAY8 IIC通讯下 硬件实现
  • 解决WPF短暂的白色闪烁(白色闪屏)
  • 从智能提效到产品赋能的架构实践
  • Pycharm and Flask 的学习心得(9)
  • PCB 通孔是电容性的,但不一定是电容器
  • CSS相关知识
  • 基于PyTorch的残差网络图像分类实现指南
  • 如何理解Pytorch中前向传播的计算过程
  • 小土堆pytorch--神经网络搭建小实战Sequential的使用
  • 高可用 Redis 服务架构分析与搭建
  • 【C/C++】从零开始掌握Kafka
  • P2676 [USACO07DEC] Bookshelf B
  • 电商小程序店铺详情页:头部无限分类与筛选功能实现
  • LabVIEW实战项目推荐与学习建议
  • 打卡第28天:装饰器
  • 【HarmonyOS5】DevEco Studio 预览器与模拟工具详解
  • 掌握聚合函数:COUNT,MAX,MIN,SUM,AVG,GROUP BY和HAVING子句的用法,Where和HAVING的区别
  • TIGER - 一个轻量高效的语音分离模型,支持人声伴奏分离、音频说话人分离等 支持50系显卡 本地一键整合包下载
  • 【Android】非System用户下Persist应用不自动拉起
  • 破解C/C++内存分配与管理:内存对象模型硬核剖析
  • LeetCode-图论-岛屿数量+腐烂的橘子
  • Leetcode 3103. 查找热门话题标签 II
  • 仓鼠找sugar--lca+图论判断点在路径
  • LangChain02-Agent与Memory模块
  • git子模块--命令--列表版
  • 机器学习——支持向量机SVM