I'm compiling a C++ program to run in a freestanding environment and the CPU I'm running on defines a 32-bit peripheral register to be available (edit: memory-mapped) at PERIPH_ADDRESS
(aligned correctly, and not overlapping with any other C++ object, stack etc.).
I compile the following code with PERIPH_ADDRESS
predefined, later link it with a full program and run it.
#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;
}
Does any of the get_value
functions (either directly or through p
/q
) have undefined behavior? If yes, can I fix it?
I think an equivalent question would be: Can any conforming compiler refuse to compile the expected program for me? For example, one with UB sanitezer turned on.
I have looked at [basic.stc.dynamic.safety] and [basic.compound#def:object_pointer_type] but that seems to only restrict the validity of pointers to dynamic objects. I don't think it applies to this code, because the "object" at PERIPH_ADDRESS
is never assumed to be dynamic. I think I can safely say that the storage denoted by p
never reaches the end of its storage duration, it can be considered static.
I've also looked at Why does C++ disallow the creation of valid pointers from a valid address and type? and the answers given to that question. They also only refer to dynamic objects' addresses and their validity, so they do not answer my question.
Other questions I've considered but couldn't answer myself that might help with the main question:
- Do I run into any UB issues because the object was never constructed within the C++ abstract machine?
- Or can I actually consider the object to be one with static storage duration "constructed" properly?
Obviously, I'd prefer answers that reference any recent C++ standard.