c++ - 通过重新解释转换将 constexpr 值转换为指针

标签 c++ pointers casting constexpr

来自 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

至于它是否实用 – 好吧,它可以编译,但尝试将 constexprreinterpret_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/

相关文章:

c++ - Boost 1_65_1 不使用 OpenSSL 1.1.0g "undefined reference"编译,但使用 "nm"找到

c++ - 通过派生模板类的正确类型转换从基类访问数据

c++ - GLSL - 给定顶点法线计算表面法线

c - 将二维数组传递给函数

java - 当父类(super class)未实现接口(interface)但子类实现时,在接口(interface)子类和父类(super class)之间进行转换

c++ - 如何正确扩展类

pointers - 如何存储指针指向的地址?

c - 如何返回 char 指针数组?我的代码有什么问题?

sockets - 如何在 swift 中将 sockaddr 转换为 sockaddr_in

java - 为什么会收到 ClassCastException 以及如何修复它?