C语言 如何在不触发指针的情况下将指针值转换为指针地址

7rtdyuoh  于 2023-10-16  发布在  其他
关注(0)|答案(3)|浏览(116)

我有以下变量

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]
7dl7o3gd

7dl7o3gd1#

要处理整数到 * 对象 * 指针的转换,请使用可选的整数uintptr_tintptr_t类型。函数指针是另一回事。
以下类型指定了一个无符号整数类型,其属性是指向void的任何有效指针都可以转换为该类型,然后转换回指向void的指针,结果将与原始指针C11dr 7.20.1.4 1进行比较

uintptr_t

然后将void *转换为所需的类型。

#include <stdint.h>
uintptr_t Value = 0x80;
uint32_t *Pointer = (void *) Value;

如果0x80不是从有效的uint32_t *派生的,则结果为 undefined behavior(UB)。然而,听起来OP是在一个具有内存Map数据位置的平台上。

0ejtzxu1

0ejtzxu12#

我来给你解释一下:给定

uint32_t Value = 0x80;

你想

*((uint32_t *)(uintptr_t)Value) = 2;

类型uintptr_t,* 如果它存在 ,保证可以在任意指针类型之间转换而不会丢失信息。它不一定存在,但是在它不存在的平台上,如果没有更多的信息,你就不能安全地做你想做的事情。
没有任何其他类型被官方保证具有此属性;然而,“cpp加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从不涉及地址算术;如果从0x80uintptr_t的强制转换实际上截断了常量,编译器可能会抱怨,但这不应该发生在您以这种方式访问的真实的内存地址上。

3htmauhk

3htmauhk3#

好吧,比sizeof(uintptr_t)至少没有最大指针类型那么大的疯狂ABI更重要的是记住指针出处强制。
你应该能够在(void *)和uintptr_t之间进行转换,通过uintptr_t,你可以使用(void *)arg“blind cookie”来传递,例如int或unsigned int(最多做一个static_assert(sizeof(int)<= sizeof(uintptr_t),以清除设计上的疯狂破坏平台)。
但是不要通过uintptr_t * 创建 * 指针,或者以其他方式操作它:它不会有正确的出处,如果你试图解引用那个指针,像CHERRY这样的体系结构会出错并中止程序。也就是说,把它看作是 * 有效 * 指针的单行道:它可以成为一个整数类型,但它不能回到指针。
这就是为什么,如果您需要在API中使用盲cookie,您可以使用(void *)而不是最大整数类型或uintptr_t本身。这允许有效的指针,以及将不会被解引用为cookie内容的指针。

相关问题