我有以下变量
uint32_t Value = 0x80
0x80 代表内存中的地址,例如
// Write 2 at address 0x80
*(uint32_t*)((uint32_t)0x80) = 2;
如何将 Value 转换为指针,使其指向 0x80?
uint32_t *Pointer = ?? Value;
这个:
(uint32_t*)(uint32_t)Value;
返回:
warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
要处理整数到 object 指针的转换,请使用可选的整数
uintptr_t
或 intptr_t
类型。函数指针是另一回事。
以下类型指定无符号整数类型,其属性是任何指向
的有效指针都可以转换为该类型,然后转换回指向void
的指针,结果将与原始指针 C11dr 7.20 进行比较。 1.4 1void
uintptr_t
然后将
void *
转换为所需的类型。
#include <stdint.h>
uintptr_t Value = 0x80;
uint32_t *Pointer = (void *) Value;
如果 0x80 不是从有效的
uint32_t *
派生的,则会导致未定义的行为 (UB)。然而,听起来 OP 是在一个具有内存映射数据位置的平台上。
我会为你拼出:给定
uint32_t Value = 0x80;
你想要
*((uint32_t *)(uintptr_t)Value) = 2;
类型
uintptr_t
,如果存在,保证可以在任意指针类型之间进行转换,而不会丢失信息。不能保证它存在,但在它不存在的平台上,如果没有大量更多信息,您尝试做的事情就无法安全地完成。
官方不保证其他类型具有此属性;然而,“cpp plus 1”是正确的,
size_t
通常也是正确的。我什至可以说,任何用于平面内存架构的 ABI(不使 size_t
具有此属性)都被错误地指定,但它们确实存在,有时您必须使用它们。
最好首先声明
Value
为指针类型:
uint32_t *const Value = (uint32_t *)(uintptr_t)0x80;
因为这样你只需在初始化时编写强制转换,而不是在使用时编写,
*Value = 2;
并且您可能有很多地方使用它。这也避免了如果发生
sizeof(uintptr_t) < sizeof(uint32_t)
时出现的潜在问题,因为uint32_t
从不参与地址运算;如果从 0x80
到 uintptr_t
的转换实际上截断了常量,编译器可能会抱怨,但是对于您以这种方式访问的真实内存地址来说,这种情况不应该发生。
好吧,比 sizeof(uintptr_t) 至少不与最大指针类型一样大的疯狂 ABI 更重要的是要记住指针来源强制执行。
您应该能够在 (void *) 和 uintptr_t 之间进行转换,并且通过 uintptr_t,您可以使用 (void *)arg“盲 cookie”来传递,例如 int 或 unsigned int (只需执行 static_assert( sizeof(int) <= sizeof (uintptr_t) at most, to weed out insanely broken-by-design platforms).
但不要通过 uintptr_t create 指针,或以其他方式操纵它:这不会有正确的出处,如果您尝试取消引用该指针,CHERRY 等架构会出错并中止程序。 IE。将其视为 valid 指针的单向街道:它可以变成整数类型,但不能变回指针。
这就是为什么,如果您在 API 中需要盲 cookie,请使用 (void *) 而不是最大整数类型或 uintptr_t 本身。这允许有效的指针,以及任何适合掩码作为指针而不会被取消引用的 cookie 内容。