现代 C++ 将 constexpr const 指针指向嵌入式应用程序的易失性内存位置的方法是什么?

What is the modern C++ way of having a constexpr const pointer to a volatile memory location for embedded applications?

提问人:Cameron Tacklind 提问时间:2/2/2019 最后编辑:Cameron Tacklind 更新时间:3/17/2022 访问量:481

问:

在嵌入式微处理器上构建用于控制硬件的库时,一个常见的任务是操作特定内存位置的位以控制硬件功能。

在 AVR 处理器中,Atmel(现在的 Microchip)提供了扩展为如下内容的宏:

#define PORTA (*(volatile uint8_t *)(0x25))

这样可以实现以下功能:

PORTA |= 1;

现在在 C++11(和更新版本)中,几乎任何用法都替换为 。#defineconstexpr

在旧版本的 GCC C++ 编译器 (4.9.2) 中,编译了以下内容:

#include <avr/io.h>
constexpr volatile uint8_t *const PortA = &PORTA;

在版本 8.2.0 中,上述内容无法编译并给出错误:

error: 'reinterpret_cast<volatile uint8_t* {aka volatile unsigned char*}>(37)' is not a constant expression

我不是在寻找为什么你不能在上下文中使用或为什么整数到指针的转换是非法的解释。reinterpret_castconstexpr

在现代 C++ 中拥有指向易失性内存的 constexpr 指针的正确方法是什么?

我已经看到将内存地址存储在 a 中然后在运行时将其用于位操作的建议。PORTAconstexpr uintptr_treinterprect_castvolatile uint8_t * const

例如,这可以工作,甚至可以按预期编译为单个指令。sbiavr-gcc

#include <stdint.h>
constexpr uintptr_t PortA = 0x25;
void set() { *((volatile uint8_t *)(PortA)) |= 1; }

但是,它需要相当数量的丑陋样板才能用作它预期的指针。PortA

这也有一个问题,似乎无法直接使用宏。相反,我们被迫对内存地址进行硬编码,这破坏了某些理想的可移植性功能。PORTA0x25

感觉我错过了一些明显的东西,购买我的搜索没有产生任何成果。

例如,这感觉像是一个“地址常量表达式”,但这似乎与引用静态分配的值有关,例如这不是我想要的。const

const char str[] = "FooBar";
constexpr const char * x = str + 2;
11 转换 C++17 易失性

评论

2赞 HEKTO 2/3/2019
我无法重现您的错误消息。我的编译器(g++ 7.3.0)吐出一条不同的消息 - .这也很奇怪......error: reinterpret_cast from integer to pointererror: value ‘37’ of type ‘volatile uint8_t* {aka volatile unsigned char*}’ is not a constant expression
0赞 Igor Tandetnik 2/3/2019
会做你想做的事吗?volatile uint8_t& PortA = PORTA;
0赞 Cameron Tacklind 12/19/2021
@IgorTandetnik 这不适用于 constexpr。我在 HEKTO 上遇到同样的错误。
0赞 Swift - Friday Pie 12/21/2021
对于指向非 const 变量的指针是 constexpr,必须在函数内部声明指针。
1赞 Fatih BAKIR 3/17/2022
@CameronTacklind,你检查过kvasir吗?看看这个:github.com/kvasir-io/Kvasir/blob/master/Lib/Chip/CM4/Nordic/......它们执行您排除的数字 + 运行时技巧,但由于它们从 SVD 文件自动生成这些标头,因此实际上没有维护负担。constexprreinterpret_cast

答:

0赞 ecatmur 3/17/2022 #1

不能创建由非常量表达式初始化的 constexpr 指针。但是,您可以创建一个指针:static const

static uint8_t volatile* const PortA = &PORTA;

或者,更好的是,参考:static

static uint8_t volatile& PortA = PORTA;