我正在编译一个在独立环境中运行的 C++ 程序,我正在运行的 CPU 定义了一个可用的 32 位外围寄存器(编辑:内存映射)在 PERIPH_ADDRESS
(正确对齐,不与任何其他 C++ 对象、堆栈等重叠)。
我使用预定义的 PERIPH_ADDRESS
编译以下代码,然后将其与完整程序链接并运行。
#include <cstdint>
struct Peripheral {
const volatile uint32_t REG;
};
static Peripheral* const p = reinterpret_cast<Peripheral*>(PERIPH_ADDRESS);
uint32_t get_value_1() {
return p->REG;
}
static Peripheral& q = *reinterpret_cast<Peripheral*>(PERIPH_ADDRESS);
uint32_t get_value_2() {
return q.REG;
}
extern Peripheral r;
// the address of r is set in the linking step to PERIPH_ADDRESS
uint32_t get_value_3() {
return r.REG;
}
是否有任何 get_value
函数(直接或通过 p
/q
)有未定义的行为?如果是,我可以修复它吗?
我认为一个等价的问题是:任何符合标准的编译器都可以拒绝为我编译预期的程序吗?例如,打开了 UB sanitizer 的一个。
我看过[ basic.stc.dynamic.safety ] 和 [ basic.compound#def:object_pointer_type ] 但这似乎只限制了指向动态对象的指针的有效性。我认为它不适用于这段代码,因为 PERIPH_ADDRESS
中的“对象”从未被假定为动态的。我想我可以有把握地说,p
表示的存储永远不会达到其存储持续时间的终点,它可以被视为静态。
我也看过 Why does C++ disallow the creation of valid pointers from a valid address and type?以及对该问题的回答。它们也只引用动态对象的地址及其有效性,所以它们没有回答我的问题。
我考虑过但无法回答自己但可能有助于解决主要问题的其他问题:
- 我是否遇到任何 UB 问题,因为该对象从未在 C++ 抽象机中构造过?
- 或者我真的可以将对象视为具有正确“构造”的静态存储持续时间的对象吗?
显然,我更喜欢引用任何最新 C++ 标准的答案。
最佳答案
从指针转换的含义是实现定义的 [expr.reinterpret.cast]
A value of integral type or enumeration type can be explicitly converted to a pointer. A pointer converted to an integer of sufficient size (if any such exists on the implementation) and back to the same pointer type will have its original value; mappings between pointers and integers are otherwise implementation-defined.
因此这是明确定义的。如果您的实现向您保证强制转换的结果是有效的,那么您没问题。†
链接的问题是关于指针运算的,这与手头的问题无关。
† 根据定义,一个 valid pointer指向一个对象,意味着后续的间接寻址也是明确定义的。应注意确保对象是 within its lifetime .
关于c++ - 通过预定义的静态地址访问寄存器是 C++ 中未定义的行为吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53213699/