uint64_t 类型的参数与 void* 类型的参数不兼容

Argument of type uint64_t is incompatible with parameter of type void*

我有一个函数 foo(void* pBuf)。我需要向它传递一个 64 位地址,但是当我按值传递时似乎无法获得正确的类型转换。

示例:foo(地址)。其中- uint64_t 地址=0x00000000DEADBEEF

编辑:使用 ARM 编译器进行编译。

uint64_t foo(void *pBuf){
    uint64_t retAddr = (uint64_t) pBuf;
    retAddr += 0x100000;
    return retAddr;
}

我在 32 位 ARM 上 sizeof(void *)4

说明:为什么我需要 32 位 ARM 上的 64 位地址? 因为我的内存映射使用36位寻址。

这样称呼它:

uint64_t address = 0xDEADBEEF;
foo((void*)address);

也就是说,您将地址强制转换为与函数签名兼容的空指针。

您不应为地址使用 64 位类型,因为它是 32 位(或任何非 64 位)系统的未定义行为。

相反,更喜欢使用 uintptr_t,这是标准的 C。 请参阅 this question for more details or this page 以获取参考。

那么解决方案可能是:

uintptr_t address = 0xDEADBEEF;   /* will trigger a warning if the constant is > max possible memory size */
foo((void*)address);

注意:如果 uintptr_t 在您的系统上不可用,size_t 通常是不错的第二选择。

第2部分 :

看起来,在您改写的问题中,您想要将地址转换为 64 位整数。

在这种情况下,由于宽度的潜在差异,从 ptr 直接转换为整数可能会触发编译器警告。

更喜欢双重演员: uint64_t value = (uint64_t)(size_t) ptr;

我可以想到两种方法来解决这个问题。通过第一种方式调用 foo 得到了我的问题的解决方案

  1. foo((void*)(uint32_t)地址)

这之所以有效,是因为我对 foo 的输入始终是 32 位值。返回值可以是64位。

  1. 当然,正确的解决方法是更改​​ foo 本身,如果我可以修改它的话。 我可以传递 foo(&address)。在 foo 内部,retAddr = *pBuf。

感谢大家的建议!

很抱歉打扰这个问题,但 none 这些答案对我来说似乎是合理的。这是一个相当简单的类型转换问题。似乎人们在 32 位系统上使用 64 位寻址,而这很容易用于外围设备或除系统本身之外的其他地址 space。

在 OP 的情况下,直接转换为 uint64_t 会导致未定义的行为,因为 void * 中不存在额外的四个字节。在 M4 调用约定的情况下,p 通常会在单个寄存器中传递,很可能是 r0uint64_t 没有额外的高位字节作为别名,因此您的编译器正确地为此发出警告。

在 GCC 7.3 arm-none-eabi 端口下,void * 可以安全地转换为 size_t (又名 unsigned int),因为它们的大小和对齐方式都是 4.完成后,您可以通过分配安全地将 unsigned int 提升为 uint64_t(又名 unsigned long long int)。促销是比演员更明确的行为。

uint64_t foo(void *p){
    uint64_t a = (size_t) p;
    a += 0x100000;
    return a;
}