如何在现代C++中将多块不同地址的数组视为单一连续数组?
现代C++实现跨固定地址数组的连续访问封装
针对单片机开发中固定地址分散数组的问题,我们可以用C++2x特性封装一个类,将两块物理不连续的数组抽象为逻辑连续的容器,支持随机访问、迭代器和标准库算法,无需手动处理索引切换。
1. 静态分配固定地址数组
保留原有的section属性配置,根据编译期常量CONF_BUFF_SIZE和BUFF_MAX分配两块数组:
#include <cstddef> // 编译期常量(根据项目实际配置) constexpr std::size_t BUFF_MAX = 800; constexpr std::size_t CONF_BUFF_SIZE = 1200; // 第一块固定地址数组(0x1000,SRAM_BANK2) alignas(unsigned char) unsigned char buffer1[std::min(CONF_BUFF_SIZE, BUFF_MAX)] __attribute__((section("SRAM_BANK2"))); // 第二块固定地址数组(仅当容量超限时分配,0xF000,SRAM_BANK4) #ifdef CONF_BUFF_SIZE > BUFF_MAX alignas(unsigned char) unsigned char buffer2[CONF_BUFF_SIZE - BUFF_MAX] __attribute__((section("SRAM_BANK4"))); #endif
2. 封装连续访问类
实现SplitBuffer类,封装两块数组的指针和大小,重载operator[]并实现随机访问迭代器,让外部使用时完全感知不到数组的物理分散:
#include <iterator> class SplitBuffer { public: using value_type = unsigned char; using pointer = value_type*; using reference = value_type&; using const_reference = const value_type&; using size_type = std::size_t; using difference_type = std::ptrdiff_t; // 随机访问迭代器 class iterator { public: using iterator_category = std::random_access_iterator_tag; using value_type = SplitBuffer::value_type; using pointer = SplitBuffer::pointer; using reference = SplitBuffer::reference; using difference_type = SplitBuffer::difference_type; constexpr iterator(pointer first_buf, size_type first_size, pointer second_buf, size_type second_size, size_type pos) : first_buf_(first_buf), first_size_(first_size), second_buf_(second_buf), second_size_(second_size), pos_(pos) {} constexpr reference operator*() const { return pos_ < first_size_ ? first_buf_[pos_] : second_buf_[pos_ - first_size_]; } constexpr pointer operator->() const { return pos_ < first_size_ ? &first_buf_[pos_] : &second_buf_[pos_ - first_size_]; } constexpr iterator& operator++() { return ++pos_, *this; } constexpr iterator operator++(int) { auto tmp = *this; ++pos_; return tmp; } constexpr iterator& operator--() { return --pos_, *this; } constexpr iterator operator--(int) { auto tmp = *this; --pos_; return tmp; } constexpr iterator operator+(difference_type n) const { return iterator(first_buf_, first_size_, second_buf_, second_size_, pos_ + n); } constexpr iterator& operator+=(difference_type n) { return pos_ += n, *this; } constexpr iterator operator-(difference_type n) const { return iterator(first_buf_, first_size_, second_buf_, second_size_, pos_ - n); } constexpr iterator& operator-=(difference_type n) { return pos_ -= n, *this; } constexpr difference_type operator-(const iterator& other) const { return pos_ - other.pos_; } constexpr reference operator[](difference_type n) const { return *(*this + n); } constexpr bool operator==(const iterator& other) const = default; constexpr auto operator<=>(const iterator& other) const = default; private: pointer first_buf_; size_type first_size_; pointer second_buf_; size_type second_size_; size_type pos_; }; // 常量随机访问迭代器 class const_iterator { public: using iterator_category = std::random_access_iterator_tag; using value_type = SplitBuffer::value_type; using pointer = const value_type*; using reference = const value_type&; using difference_type = SplitBuffer::difference_type; constexpr const_iterator(pointer first_buf, size_type first_size, pointer second_buf, size_type second_size, size_type pos) : first_buf_(first_buf), first_size_(first_size), second_buf_(second_buf), second_size_(second_size), pos_(pos) {} constexpr reference operator*() const { return pos_ < first_size_ ? first_buf_[pos_] : second_buf_[pos_ - first_size_]; } constexpr pointer operator->() const { return pos_ < first_size_ ? &first_buf_[pos_] : &second_buf_[pos_ - first_size_]; } constexpr const_iterator& operator++() { return ++pos_, *this; } constexpr const_iterator operator++(int) { auto tmp = *this; ++pos_; return tmp; } constexpr const_iterator& operator--() { return --pos_, *this; } constexpr const_iterator operator--(int) { auto tmp = *this; --pos_; return tmp; } constexpr const_iterator operator+(difference_type n) const { return const_iterator(first_buf_, first_size_, second_buf_, second_size_, pos_ + n); } constexpr const_iterator& operator+=(difference_type n) { return pos_ += n, *this; } constexpr const_iterator operator-(difference_type n) const { return const_iterator(first_buf_, first_size_, second_buf_, second_size_, pos_ - n); } constexpr const_iterator& operator-=(difference_type n) { return pos_ -= n, *this; } constexpr difference_type operator-(const const_iterator& other) const { return pos_ - other.pos_; } constexpr reference operator[](difference_type n) const { return *(*this + n); } constexpr bool operator==(const const_iterator& other) const = default; constexpr auto operator<=>(const const_iterator& other) const = default; private: pointer first_buf_; size_type first_size_; pointer second_buf_; size_type second_size_; size_type pos_; }; constexpr SplitBuffer(pointer first_buf, size_type first_size, pointer second_buf, size_type second_size) : first_buf_(first_buf), first_size_(first_size), second_buf_(second_buf), second_size_(second_size) {} // 获取总容量 constexpr size_type size() const { return first_size_ + second_size_; } // 随机访问重载 constexpr reference operator[](size_type idx) { return idx < first_size_ ? first_buf_[idx] : second_buf_[idx - first_size_]; } constexpr const_reference operator[](size_type idx) const { return idx < first_size_ ? first_buf_[idx] : second_buf_[idx - first_size_]; } // 迭代器接口 constexpr iterator begin() { return iterator(first_buf_, first_size_, second_buf_, second_size_, 0); } constexpr iterator end() { return iterator(first_buf_, first_size_, second_buf_, second_size_, size()); } constexpr const_iterator begin() const { return const_iterator(first_buf_, first_size_, second_buf_, second_size_, 0); } constexpr const_iterator end() const { return const_iterator(first_buf_, first_size_, second_buf_, second_size_, size()); } constexpr const_iterator cbegin() const { return begin(); } constexpr const_iterator cend() const { return end(); } private: pointer first_buf_; size_type first_size_; pointer second_buf_; size_type second_size_; };
3. 全局实例化与使用
根据编译期条件初始化全局SplitBuffer实例,之后即可像操作普通连续数组一样使用:
// 全局缓冲实例 #ifdef CONF_BUFF_SIZE > BUFF_MAX constexpr SplitBuffer global_buffer(buffer1, sizeof(buffer1)/sizeof(buffer1[0]), buffer2, sizeof(buffer2)/sizeof(buffer2[0])); #else constexpr SplitBuffer global_buffer(buffer1, sizeof(buffer1)/sizeof(buffer1[0]), nullptr, 0); #endif // 使用示例 int main() { // 修改第二块数组的元素(假设CONF_BUFF_SIZE=1200,BUFF_MAX=800) global_buffer[1000] = 0xFE; // 范围for遍历初始化 for (auto& byte : global_buffer) { byte = 0x00; } // 使用标准库算法 #include <algorithm> std::fill(global_buffer.begin(), global_buffer.end(), 0xFF); return 0; }
关键特性说明
- 编译期计算:所有大小判断和实例化均在编译期完成,无运行时额外开销
- 标准容器兼容:实现随机访问迭代器,支持所有C++标准库算法
- 透明封装:外部无需关心数组物理分散,操作逻辑与连续数组完全一致
- 静态内存安全:保留原有固定地址分配,符合单片机内存约束
内容的提问来源于stack exchange,提问作者ATL_DEV
相关产品推荐
相关产品推荐

