C/C++ 结构体:. 与 -> 的区别与用法及其STM32中的使用
目录
-
引言
-
一、深入理解 C/C++ 结构体:
.
与->
的区别与用法- 1.
.
(点运算符)详解 - 2.
->
(箭头运算符)详解 - 3.
.
与->
的等价与转换 - 4. 常见错误与调试技巧
- 5. C++ 特性与运算符重载
- 6. 实战案例:链表与智能指针
- 7. 最佳实践与性能考量
- 1.
-
二、在 STM32 单片机中,结构体的
.
与->
使用详解- 1. 外设寄存器访问:
->
的绝对主场 - 2. 库函数配置:
.
与->
的混合使用 - 3. 动态分配与回调:
->
的灵活应用 - 4. 常见错误与避坑指南
- 5. 实战技巧与性能优化
- 1. 外设寄存器访问:
-
三、综合总结
引言
结构体(struct
)在 C/C++ 及嵌入式开发中广泛应用。访问结构体成员时,使用点运算符(.
)或箭头运算符(->
)是基础操作。本文分为两大部分:
- 深入理解 C/C++ 结构体:讲解
.
与->
的原理与用法,包括调试与最佳实践。 - 在 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; | — | 添加空指针检查 |
调试技巧:
- 使用 GDB:
p stu1
vsp *stu_ptr
- 加断言:
assert(ptr); ptr->field;
- 使用 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. 最佳实践与性能考量
- 优先使用智能指针与容器
- 注意结构体对齐与缓存友好
- 简化多级解引用为
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()
) - 关注结构体对齐与数据局部性,提高缓存友好性
相关文章:
C/C++ 结构体:. 与 -> 的区别与用法及其STM32中的使用
目录 引言 一、深入理解 C/C 结构体:. 与 -> 的区别与用法 1. .(点运算符)详解2. ->(箭头运算符)详解3. . 与 -> 的等价与转换4. 常见错误与调试技巧5. C 特性与运算符重载6. 实战案例:链表与智能…...

docker中使用openresty
1.为什么要使用openresty 我这边是因为要使用1Panel,第一个最大的原因,就是图方便,比较可以一键安装。但以前一直都是直接安装nginx。所以需要一个过度。 2.如何查看openResty使用了nginx哪个版本 /usr/local/openresty/nginx/sbin/nginx …...
Jetpack Compose 中更新应用语言
在 Jetpack Compose 应用中更新语言需要结合传统的 Android 语言配置方法和 Compose 的重组机制。以下是完整的实现方案: 1. 创建语言管理类 object LocaleManager {private var currentLocale: Locale Locale.getDefault()fun setLocale(context: Context, local…...

Java 中的 super 关键字
个人总结: 1.子类构造方法中没有显式使用super,Java 也会默认调用父类的无参构造方法 2.当父类中没有无参构造方法,只有有参构造方法时,子类构造方法就必须显式地使用super来调用父类的有参构造方法。 3.如果父类没有定义任何构造…...
CMake基础:CMakeLists.txt 文件结构和语法
目录 1.CMakeLists.txt基本结构 2.核心语法规则 3.关键命令详解 4.常用预定义变量 5.变量和缓存 6.变量作用域与传递 7.注意事项 1.CMakeLists.txt基本结构 CMakeLists.txt 是 CMake 构建系统的核心配置文件,采用命令式语法组织项目结构和编译流程。主要用于…...

PCM音频数据的编解码
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么?二、使用步骤 1.引入库2.读入数据 总结 前言 提示:这里可以添加本文要记录的大概内容: 例如:…...
WebView2 Win7下部分机器触屏失效的问题
这个问题官方给了解决的方案,相关地址,只需要在项目中运行这个代码即可 public static void DisableWPFTabletSupport(){TabletDeviceCollection devices Tablet.TabletDevices;if (devices.Count > 0){Type inputManagerType typeof(InputManager)…...

Ubuntu 通过指令远程命令行配置WiFi连接
前提设备已经安装了无线网卡。 1、先通过命令行 ssh 登录机器。 2、搜索wifi设备,指令如下: sudo nmcli device wifi 3、输入需要联接的 wifi 名称和对应的wifi密码,指令如下: sudo nmcli device wifi connect wifi名称 passw…...
线程池优雅关闭的哲学
引言 关于并发的哲学,本文将着重强调那些关于线程池优雅关闭的一些技巧,希望对你有所启发。 强制关闭线程池的弊端 对于池化的线程池,如果采用强制关闭的方式将线程池直接关闭,就可能存在上下文消息消息,无法的很好…...
11.8 LangGraph生产级AI Agent开发:从节点定义到高并发架构的终极指南
使用 LangGraph 构建生产级 AI Agent:LangGraph 节点与边的实现 关键词:LangGraph 节点定义, 条件边实现, 状态管理, 多会话控制, 生产级 Agent 架构 1. LangGraph 核心设计解析 LangGraph 通过图结构抽象复杂 AI 工作流,其核心要素构成如下表所示: 组件作用描述代码对应…...

8天Python从入门到精通【itheima】-41~44
目录 41节-while循环的嵌套应用 1.学习目标 2.while循环的伪代码和生活情境中的应用 3.图片应用的代码案例 4.代码实例【Patrick自己亲手写的】: 5.whlie嵌套循环的注意点 6.小节总结 42节-while循环的嵌套案例-九九乘法表 1.补充知识-print的不换行 2.补充…...

深度图数据增强方案-随机增加ROI区域的深度
主要思想:随机增加ROI区域的深度,模拟物体处在不同位置的形态。 首先打印一张深度图中的深度信息分布: import cv2 import matplotlib.pyplot as plt import numpy as np import seaborn as sns def plot_grayscale_histogram(image_path)…...
[Java恶补day6] 15. 三数之和
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k ,同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有和为 0 且不重复的三元组。 注意:答案中不可以包含重复的三元组。 示例 1&a…...
Django模板及表单
什么是Django模板 Django模板是一种用于生成动态内容的文件,它使用Django模板语言(Django Template Language,简称DTL)来描述和渲染HTML页面。模板允许开发人员将动态数据与静态HTML结构分离,以实现更灵活和可维护的W…...

两个mysql的maven依赖要用哪个?
背景 <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId> </dependency>和 <dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId> &l…...

Kafka Consumer工作流程
Kafka Consumer工作流程图 1、启动与加入组 消费者启动后,会向 Kafka 集群中的某个 Broker 发送请求,请求加入特定消费者组。这个 Broker 中的消费者协调器(Consumer Coordinator)负责管理消费者组相关事宜。 2、组内分区分配&am…...

大腾智能 PDM 系统:全生命周期管理重塑制造企业数字化转型路径
在当今激烈的市场竞争中,产品迭代速度与质量已成为企业生存与发展的核心命脉。面对客户需求多元化、供应链协同复杂化、研发成本管控精细化等挑战,企业亟需一套能够贯穿产品全生命周期的数字化解决方案。 大腾智能PDM系统通过构建覆盖设计、研发、生产、…...
GATT 服务的核心函数bt_gatt_discover的介绍
目录 概述 1 GATT 基本概念 1.1 GATT 的介绍 1.2 GATT 的角色 1.3 核心组件 1.4 客户端操作 2 bt_gatt_discover函数的功能和应用 2.1 函数介绍 2.1 发现类型(Discover Type) 3 典型使用流程 3.1 服务发现示例 3.2 级联发现模式 3.3 按UUID过…...

【短距离通信】【WiFi】WiFi7关键技术之4096-QAM、MRU
目录 3. 4096-QAM 3.1 4096-QAM 3.2 QAM 的阶数越高越好吗? 4. MRU 4.1 OFDMA 和 RU 4.2 MRU 资源分配 3. 4096-QAM 摘要 本章主要介绍了Wi-Fi 7引入的4096-QAM对数据传输速率的提升。 3.1 4096-QAM 对速率的提升 Wi-Fi 标准一直致力于提升数据传输速率&a…...
C 语言学习笔记
文章目录 程序设计入门 --- C 语言第一周 程序设计与 C 语言1 计算机与编程语言:计算机怎么做事情的,编程语言是什么📒 1.1 计算机的普遍应用 —— 离了它,现代人可能不会“活”了**🌐 科学计算:计算机的“最强大脑”时刻****📊 数据处理:现代社会的“数字管家”***…...
【MySQL成神之路】MySQL函数总结
以下是MySQL函数的全面总结,包含概念说明和代码示例: 一、MySQL函数分类 1. 字符串函数 -- CONCAT:连接字符串 SELECT CONCAT(Hello, , World); -- 输出 Hello World -- SUBSTRING:截取子串 SELECT SUBSTRING(MySQL, 2, 3…...

线程池实战——数据库连接池
引言 作者在前面写了很多并发编程知识深度探索系列文章,反馈得知友友们收获颇丰,同时我也了解到友友们也有了对知识如何应用感到很模糊的问题。所以作者就打算写一个实战系列文章,让友友们切身感受一下怎么应用知识。话不多说,开…...
修改 vue-pdf 源码升级 pdfjs-dist 包, 以解决部分 pdf 文件显示花屏问题
文章目录 背景: 客户反馈有部分文件预览花屏 最终解决方案: 自己 fork vue-pdf 仓库, 修改 pdfjs-dist 版本, 升级到 3.3.122 (我是 vue2 项目 node 10 环境)修改源码中引用地址带有 pdfjs-dist/es5/ 的地方, 去掉 es5 , 另外如果还有报错自己搜一下 pdfjs-dist/ , 看看引用…...

基于moonshot模型的Dify大语言模型应用开发核心场景
基于moonshot模型的Dify大语言模型应用开发核心场景学习总结 一、Dify环境部署 1.Docker环境部署 这里使用vagrant部署,下载vagrant之后,vagrant up登陆,vagrant ssh,在vagrant 中使用 vagrant centos/7 init 快速创建虚拟机 安装…...

华为OD机试真题——字符串序列判定(2025B卷:100分)Java/python/JavaScript/C/C++/GO最佳实现
2025 B卷 100分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分…...
在Java的list.forEach(即 Stream API 的 forEach 方法)中,无法直接使用 continue 或 break 语句的解决办法
说明 在 Java 的 list.forEach(即 Stream API 的 forEach 方法)中,无法直接使用 continue 或 break 语句,因为它是一个终结操作(Terminal Operation),依赖于 Lambda 表达式或方法引用。 有些时…...
Java面向对象高级学习笔记
面向对象高级 -类变量 类变量-提出问题 提出问题的主要目的就是让大家思考解决之道,从而引出我要讲的知识点 说:有一群小孩在玩堆雪人,不时有新的小孩加入,请问如何知道现在共有多少人在玩?,编写程序解决。 类变量快速入门 思考: 如果,设计一个int co…...
LLM之Agent:Mem0的简介、安装和使用方法、案例应用之详细攻略
LLM之Agent:Mem0的简介、安装和使用方法、案例应用之详细攻略 目录 Mem0的简介 1、Mem0的特点 2、性能: Mem0的安装及使用方法 1、安装 2、基本用法(基本用法) Mem0的案例应用 Mem0的简介 Mem0(发音为“mem-ze…...

工商总局可视化模版-Echarts的纯HTML源码
概述 基于ECharts的工商总局数据可视化HTML模版,帮助开发者快速搭建专业级工商广告数据展示平台。这款模版设计规范,功能完善,适合各类工商监管场景使用。 主要内容 本套模版采用现代化设计风格,主要包含以下核心功能模块&…...

Spring AI 和 Elasticsearch 作为你的向量数据库
作者:来自 Elastic Josh Long, Philipp Krenn 及 Laura Trotta 使用 Spring AI 和 Elasticsearch 构建一个完整的 AI 应用程序。 Elasticsearch 原生集成了业界领先的生成式 AI 工具和服务提供商。查看我们关于超越 RAG 基础或使用 Elastic 向量数据库构建生产级应用…...