来自 C 和嵌入式背景,经常使用寄存器地址并将其转换为指针:
#define REG_A_ADDR 0x80000000
uint32_t ptr_reg_a = (uint32_t*) REG_A_ADDR;
但是,C++ 强调使用 constexpr
作为编译时常量,这样更安全。
以下是我想出的等效版本,但它无法编译,因为 reinterpret_cast
不能与 constexpr
一起使用,貌似:
constexpr uint32_t reg_a_addr = 0x80000000;
constexpr uint32_t *ptr_reg_a = reinterpret_cast<uint32_t*>(reg_a_addr); // constexpr variable 'reg_a_addr' must be initialized by a constant expression
那么,既然上面的代码片段出错了,解决它的实际方法是什么?使用 const
可以很好地编译,但实用吗?
最佳答案
尽管我不是完全确定您在这种情况下所说的“类型安全”1,2 是什么意思,但您可以使用const
使用适当的 ...ptr_t
类型以确保您提供的(常量)值对指针有效。
以下面的代码为例:
#include <iostream>
#include <cstdint>
// I added an extra zero to your constant - now it's too big for a 32-bit pointer
constexpr uintptr_t reg_a_addr = 0x800000000; // uintptr_t is platform-specific
uint32_t* const ptr_reg_a = reinterpret_cast<uint32_t* const>(reg_a_addr);
// ^ Note that "const unit32_t* ptr_reg_a ..." declares a pointer to a constant;
// the version I have given defines a constant pointer to (potentially) writable memory.
int main()
{
std::cout << ptr_reg_a << "\n";
return 0;
}
当使用 MSVC 定位 x64 平台时,这会在没有警告的情况下编译并产生预期的输出:
0000000800000000
但是,当针对 x86(32 位)平台时,编译器会发出值太大的警告:
warning C4305: 'initializing': truncation from '__int64' to 'const uintptr_t'
warning C4309: 'initializing': truncation of constant value
事实上,输出将是截断后的值:
00000000
至于它是否实用 – 好吧,它可以编译,但尝试将 constexpr
与 reinterpret_cast
结合使用时却不行,所以我想是的!
请注意,Visual Studio 2022 中的 clang-cl 编译器(针对 32 位时)会针对常量太大给出“等效”警告:
warning : implicit conversion from 'long long' to 'const uintptr_t' (aka 'const unsigned int') changes value from 34359738368 to 0 [-Wconstant-conversion]
1 也许,所谓“类型安全”,您的意思是在编译时将阻止向该指针重新分配新值……在这种情况下:是的,它是类型安全的,因为代码如下以下将不会编译:
uint32_t q = 42;
ptr_reg_a = &q;
error : cannot assign to variable 'ptr_reg_a' with const-qualified type 'uint32_t *const' (aka 'unsigned int *const')
2 如果您问使用 const
而不是 constexpr
是否会使这样的指针类型不那么严格,那么:否,不会的。然而,(IIRC) C++ 标准确实对 constexpr
值的潜在滥用的诊断提出了更严格的要求……但是如果完全启用警告,许多(如果不是大多数)主流编译器将为案例提供合适的诊断(比如)违反严格的别名规则,或对此类指针的其他使用表现出未定义的行为。
关于c++ - 通过重新解释转换将 constexpr 值转换为指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73029823/