讲师中心 微信公众号
AI工具推荐 视频效率加速

C++如何实现简单的环形缓冲区_C++在嵌入式通信中的数据存储【案例】

落涛大大_2943

落涛大大_2943

发布时间:2026-02-06 15:22:02

|

231人浏览过

|

来源于php中文网

原创

环形缓冲区核心是用数组模拟首尾相连队列,靠volatile head/tail指针控制读写,采用“预留空位”法判满((tail+1)&(cap-1)==head),配合位运算与DMB内存屏障实现裸机下无锁安全通信。

c++如何实现简单的环形缓冲区_c++在嵌入式通信中的数据存储【案例】

环形缓冲区的核心实现逻辑是什么

环形缓冲区本质是用数组模拟首尾相连的队列,靠两个指针(head 和 tail)控制读写位置,避免数据搬移。在嵌入式通信中,它常用于串口、CAN 或 SPI 接收中断服务程序(ISR)与主循环之间的解耦——ISR 只管往里写,主循环只管往外读,不加锁也能安全运行(前提是单生产者 + 单消费者,且不跨线程)。

关键不是“怎么封装类”,而是“怎么保证边界不越界、不覆盖、不漏读”。最简实现只需三个成员:buffer(固定大小数组)、head(下一次读的位置)、tail(下一次写的位置),以及一个预设容量 capacity。

常见错误现象:head == tail 时无法区分“空”和“满”;直接用 (tail + 1) % capacity 判断是否满,但未预留一个空位;在 ISR 中修改 tail 后没做内存屏障(ARM Cortex-M 上可能被编译器乱序优化)。

  • 推荐用“预留一个空位”法:缓冲区实际可用长度为 capacity - 1,full() 条件是 (tail + 1) % capacity == head
  • head 和 tail 必须声明为 volatile(若在 ISR 和主循环间共享),或使用 std::atomic(C++11 起,但嵌入式常禁用 STL)
  • 容量建议设为 2 的幂(如 64、256),方便用位运算替代取模:tail = (tail + 1) & (capacity - 1),省去除法开销

如何在裸机嵌入式环境里安全地用 C++ 实现

裸机(无 OS、无 STL)下不能依赖 std::queue 或 std::vector,必须手写、零动态分配、所有变量静态或栈上。典型结构体如下:

立即学习“C++免费学习笔记(深入)”;

struct RingBuffer {
    uint8_t buffer[256];
    volatile uint16_t head;
    volatile uint16_t tail;
    static const uint16_t capacity = 256;
};

注意:uint16_t 足够覆盖 64KB 缓冲区,但若容量 ≤ 256,可用 uint8_t 节省空间;volatile 是强制要求,否则编译器可能缓存 head/tail 值导致读写逻辑失效。

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载

写操作(如 UART RX ISR 中):

  • 先判断是否满:if ((tail + 1) & (capacity - 1) != head)(假设 capacity 是 2 的幂)
  • 写入:buffer[tail] = byte;
  • 更新 tail:tail = (tail + 1) & (capacity - 1);
  • 关键:在 tail 更新后加一条 __DMB();(ARM DMB 内存屏障指令),防止写 buffer 和写 tail 被重排

读操作(主循环中):

  • 检查是否空:if (head != tail)
  • 读出:byte = buffer[head];
  • 更新 head:head = (head + 1) & (capacity - 1);
  • 同样需要 __DMB()(读场景通常可省,但对称写更稳妥)

为什么不能直接用 std::array + std::atomic

在部分支持 C++11 的嵌入式工具链(如 ARM GCC 9+)中,std::atomic<uint16_t></uint16_t> 理论上可行,但实际踩坑多:

  • 某些 Cortex-M0/M0+ 芯片不支持原子加减硬件指令,std::atomic 会退化为锁实现(需全局互斥量),而裸机根本没锁基础设施
  • std::array 本身没问题,但若搭配 std::atomic 使用,编译器可能生成非紧凑代码,增加 ROM 占用
  • 标准库头文件(如 <atomic></atomic>)可能隐式拉入异常处理或 RTTI 支持,违反嵌入式“零开销抽象”原则
  • 调试困难:GDB 对 std::atomic 的 volatile 行为支持不一,容易误判读写顺序

结论:裸机环境下,显式 volatile + 手动内存屏障比依赖 std::atomic 更可控、更轻量、更容易验证。

中断与主循环共用时最容易忽略的细节

真正出问题的往往不是算法,而是上下文切换的微小疏漏:

  • 缓冲区地址必须位于非 cache 区域(如 STM32 的 SRAM1),或写完后调用 SCB_CleanDCache_by_Addr()(若开启 D-Cache);否则主循环读到的是脏 cache 数据
  • head 和 tail 必须字节对齐(自然满足),但若结构体打包(__attribute__((packed))),要确认编译器没插入填充字节破坏地址连续性
  • UART 中断若频繁触发(如 1Mbps 连续流),写操作必须极简——禁止在 ISR 里调用任何函数(包括 printf)、禁止浮点运算、禁止访问外设寄存器(除非必要)
  • 测试时别只看“能通”,要故意塞满缓冲区再突然停止发送,验证 tail 是否卡死、主循环是否持续读出旧数据

环形缓冲区的健壮性不在代码行数,而在每个内存访问是否被编译器和硬件共同尊重。

热门AI工具

更多
DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

超级麦吉

一款通过数字员工协作完成调研、数据分析与文档制作的AI办公平台。

VibeKnow
VibeKnow Hot

一款AI视频创作工具,主要用于全球首个AI知识视频创作平台,文档、文章、网页,一键生成视频,适合需要提升相关任务效率的用户。

UP简历
UP简历 Hot

一款AI办公效率工具,主要用于基于AI技术的免费在线简历制作工具,适合需要提升相关任务效率的用户。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

墨刀AI
墨刀AI Hot

一款AI图像与设计工具,主要用于产品经理的专属智能体,适合需要提升相关任务效率的用户。

讯飞智作

讯飞智作是一款AI视频创作工具,AI文本配音工具,数字人课程、营销视频制作。

二狗PPT
二狗PPT Hot

一款AI演示文稿工具,主要用于专为中式职场打造的AI PPT生成工具,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

相关专题

更多
printf用法大全
printf用法大全

php中文网为大家提供printf用法大全,以及其他printf函数的相关文章、相关下载资源以及各种相关课程,供大家免费下载体验。

828

2023.06.20

fprintf和printf的区别
fprintf和printf的区别

fprintf和printf的区别在于输出的目标不同,printf输出到标准输出流,而fprintf输出到指定的文件流。根据需要选择合适的函数来进行输出操作。更多关于fprintf和printf的相关文章详情请看本专题下面的文章。php中文网欢迎大家前来学习。

1029

2023.11.28

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

4934

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

5111

2025.07.04

c++中volatile关键字的作用
c++中volatile关键字的作用

本专题整合了c++中volatile关键字的相关内容,阅读专题下面的文章了解更多详细内容。

794

2025.10.23

C++ 智能指针与现代内存管理
C++ 智能指针与现代内存管理

深入讲解 C++ 现代内存管理的核心工具——智能指针,涵盖 unique_ptr 独占所有权语义、shared_ptr 引用计数机制与循环引用问题、weak_ptr 弱引用的应用场景、make_unique/make_shared 工厂函数的性能优势、自定义删除器的编写、RAII 资源管理思想的实践,以及从裸指针迁移到智能指针的重构策略,帮助开发者编写安全无泄漏的现代 C++ 代码。

379

2026.04.23

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

6187

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2608

2023.08.10

Gradle插件开发入门教程
Gradle插件开发入门教程

本专题介绍Gradle插件开发的基本流程,涵盖插件类编写、自定义任务注册、扩展参数设计和插件应用方法,帮助你理解插件如何组织构建逻辑,减少多个项目之间的重复配置。

120

2026.10.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn