从 uint8_t* 到 uint32_t 的无效转换 - 从 32 位架构迁移到 64 位架构时?
Posted
技术标签:
【中文标题】从 uint8_t* 到 uint32_t 的无效转换 - 从 32 位架构迁移到 64 位架构时?【英文标题】:Invalid conversion from uint8_t* to uint32_t - when migrating from 32 to 64bit architecture? 【发布时间】:2022-01-20 16:10:44 【问题描述】:我有一个小函数可以在 32 位架构上将虚拟内存地址转换为物理地址:
uint32_t VIRTBASE;
uint32_t getPhysForVirt(void* virt)
uint32_t offset = (uint8_t*)virt - VIRTBASE;
return PHYSBASE + offset;
它在过去 10 年多的时间里编译和运行,没有任何问题。
我已经更改了编译器,以便为较新的架构构建存储库(现在首次支持 64 位)。
编译失败说明
从 ‘uint8_t*’ aka ‘unsigned char*’ 到 ‘uint32_t’ aka ‘unsigned int’ 的无效转换 [-fpermissive]
现在,我理解了该消息,但我不确定使此编译没有错误的必要步骤。
我只是确定我不想启用 -fpermissive。
【问题讨论】:
VIRTBASE
是什么?
它在过去 10 年多的时间里编译和工作,没有任何问题。 什么给你的印象是,它可以以任何方式、形状或形式尝试填充任何指针变成uint32_t
?这样做的代码 - 坦率地说 - 完全是废话。如果你现在应该让它工作,你有很多工作要做。我不会相信写那个 POS 的人的任何东西(不是“销售点”......)
你甚至还没有看到它正在破坏的其他东西!直接访问 DMA 寄存器的内存并指示它将数据从这里复制到那里.. :)
我不想看 ;-)
我们确实需要更多信息来帮助您移植此代码。虚拟地址的含义还不清楚。它只是表示进程虚拟地址空间中的地址,即普通地址/指针吗?如果是这样,物理地址究竟是什么?这是用于进程间通信和共享内存中的地址,每个进程的基地址不同吗?
【参考方案1】:
您使用了错误的类型。 C 语言具有将指针转换为整数值的特殊类型。
uintptr_t VIRTBASE;
uintptr_t getPhysForVirt(const void * restrict virt)
ptrdiff_t offset = (uintptr_t)virt - VIRTBASE;
return PHYSBASE + offset;
如果其余的代码都按照这个函数的方式编写 - 你圣诞节有很多工作。
【讨论】:
en.cppreference.com/w/c/types/integer 我怀疑 OP 的调用代码和PHYSBASE
需要更新以处理新的返回类型。是的,圣诞节有很多工作。
静音DV-ter。你能解释一下我的回答中什么值得 DV 吗?【参考方案2】:
您正在执行指针运算并将其直接转换为 32 位无符号整数。
在 32 位架构上,指针也是 32 位无符号整数,因此这很可能在后台静默处理。
现在,在您的 64 位架构上,您将两个 64 位指针相减并将结果存储在一个 32 位整数中——因此丢失了一半的地址!
您可能根本不希望这个函数返回一个整数,而是一个指向您实际使用的任何数据类型的指针(可能是 uint8_t*,因为这在函数本身中有明确说明)。
编辑:相反,也许您实际上是要取消引用virt
并减去它的值,而不是进行指针运算?如果是这样,您将 *
运算符放在错误的位置。试试:
uint32_t offset = (uint8_t) *virt - VIRTBASE;
尽管正如另一位评论者指出的那样,这会导致取消引用 void 指针的问题。你必须先把它转换成有意义的东西。
【讨论】:
我会接受这个,因为它满足了我最初的问题。注意:*
运算符 not 在错误的位置,它只是在 32 位上正常工作。此函数的结果是馈入 CPU 的直接内存地址,因此试图“编译”是错误的方法。我将不得不根据 CPU 的官方文档正确地重写它。
@Daniel 使用正确的类型而不是魔法
这绝对看起来完全错误,甚至无法编译(不能在vod *
上使用一元*
)——然后你试图取消引用指针以获取单个字节从那个字节中减去 VIRTBASE,这似乎很荒谬。
@ChrisDodd ...你读过这篇文章吗?将指针减法转换为 uint32 是已经荒谬的。此外,OP 已经确认第二种解释不是他的代码中发生的事情。
将 uint32 视为地址仅在非 32 位机器上是没有意义的,用正确大小的类型替换 uint32_t 的明显修复似乎更合理以上是关于从 uint8_t* 到 uint32_t 的无效转换 - 从 32 位架构迁移到 64 位架构时?的主要内容,如果未能解决你的问题,请参考以下文章
uint8_t / uint16_t / uint32_t /uint64_t 是什么数据类型 - 大总结
uint8_t / uint16_t / uint32_t /uint64_t 是什么数据类型 - 大总结,看完全明白了
uint8_t / uint16_t / uint32_t /uint64_t 这些数据类型是什么?