Reputation: 12332
I have code like this:
constexpr int *p = (int*)0x12345678;
but the compiler (rightfully) says:
foo.cc:1:20: error: ‘reinterpret_cast’ from integer to pointer
1 | constexpr int *p = (int*)0x12345678;
| ^~~~~~~~~~~~~~~~
Is there any equivalent code or way to mark this instance of a cast to be acceptable as constexpr?
Note: In the embedded / micro-controller world having memory mapped device registers is really common but because of this one can't use constexpr for any of the code involved with them.
PS: A solution requiring gcc or clang is fine. Doesn't need to be portable.
Upvotes: 0
Views: 466
Reputation: 72356
This non-portable method appears to work using g++ 11 and GNU ld, even allowing the pointer to be used as a template argument. (clang++ does not allow it as a template argument.)
A pointer-type template argument must point at a named variable with external linkage, so I introduce a variable for the actual value, and get the linker rather than compiler to provide that variable's symbol name as a specific address.
#include <cstdio>
// Provide command-line argument -Wl,--defsym=p_var=0x12345678
extern volatile int p_var;
constexpr volatile int* p = &p_var;
constexpr volatile int* p2 = p+1;
constexpr volatile int* p3 = p2-1;
template <volatile int* P> void print_addr() {
std::printf("%p\n", const_cast<void*>(static_cast<volatile void*>(P)));
}
// After linking, the code contains constant 0x1234567c and no add instruction.
volatile int* get_p2() { return p2; }
int main() {
print_addr<p>();
// print_addr<p2>(); ERROR: invalid template argument
print_addr<p3>();
}
Some of the pointer arithmetic is actually happening at link time, not compile time, but g++ apparently doesn't mind for the purposes of C++ language requirements.
Upvotes: 1