在64位计算机上编译32位代码时,如何处理"从'void*'转换为'int'失去精度"?

bad*_*kya 32 c++ linux portability 32bit-64bit

我有一个可以在32位机器上编译和工作的软件包.我现在正试图让它在64位机器上编译并发现以下错误 -

 error: cast from ‘void*’ to ‘int’ loses precision
Run Code Online (Sandbox Code Playgroud)

是否有编译器标志来抑制这些错误?或者我是否必须手动编辑这些文件以避免这些演员表?

Ree*_*sey 50

问题是,在32位中,int(一个32位整数)将保存一个指针值.

当你移动到64位时,你不能再将指针存储在int中 - 它不足以容纳64位指针.在使用intptr_t类型设计的.


jal*_*alf 23

你的代码坏了.忽略编译器给你的警告不会破坏它.

当您尝试将64位宽指针存储为32位整数时,您认为会发生什么?一半的数据将被丢弃.我无法想象很多情况下这是正确的事情,或者它不会导致错误的地方.

修复你的代码.或者保持代码当前工作的32位平台.

如果您的编译器定义intptr_tuintptr_t使用它们,因为它们是保证足够大的整数类型来存储指针.

如果这些类型不可用,size_t或者ptrdiff_t也足够大,可以在大多数(不是所有)平台上保持指针.或者使用long(在GCC编译器上通常是64位平台上的64位)或long long(大多数但不是所有编译器都支持C99的C99类型),或者至少64位的其他实现定义的整数类型在64位平台上广泛使用.

  • +1用于引用intptr_t.如果你有一个带有(void*)的泛型函数,那么将事物从void*转换为整数类型是一个有效的用例,因为用户可以将自己的数据(可能是指针或整数)传递给它.当该用户数据随后被传递回使用它的特定代码时,它可以将其转换回整数. (3认同)

小智 14

我的猜测是OP的情况是void*被用作int的一般存储,其中void*大于int.例如:

int i = 123;
void *v = (void*)i;    // 64bit void* being (ab)used to store 32bit value
[..]
int i2 = (int)v;       // we want our 32bits of the 64bit void* back
Run Code Online (Sandbox Code Playgroud)

编译器不喜欢最后一行.

我不打算以这种方式滥用空洞来判断是对还是错.如果你真的想欺骗编译器,以下技术似乎可行,即使使用-Wall:

int i2 = *((int*)&v);
Run Code Online (Sandbox Code Playgroud)

这里它取v的地址,将地址转换为所需数据类型的指针,然后跟随指针.


sth*_*sth 11

出于某种原因这是一个错误:int只是void*你机器上的一半大,所以你不能只存储void*一个int.你会松开指针的一半,当程序稍后试图int再次指出指针时,它不会得到任何有用的东西.

即使编译器不会给出错误,代码也很可能不起作用.需要更改和检查代码以获得64位兼容性.

  • 你们都错过了这一点.他是向下转换,当你需要通过指针传递一堆数据或者只是一个整数参数时,通常会使用它.关于调用的其他东西,通常是另一个参数,告诉函数指针参数实际上是指向某些数据的指针,还是只是一个已向指针'向上'的整数.如果是后者,则需要将该指针"向下转换"回整数.警告只是 - 警告.他们不是刻在石头上的上帝的法律,像对待他们一样没有帮助. (9认同)
  • @Wexxor:不,重点在于他的系统上的指针与`int`的大小不同.指针占用大约8个字节的空间,即"int"4个字节.`int`没有足够的空间来存储指针中的所有数据,因此如果将指针转换为`int`则会丢失信息.通过向另一个方向投射,您无法获得之后丢失的这四个字节.因此,在这种情况下,将指针强制转换为"int"会丢失信息,之后您无法返回指向`int`的指针. (2认同)

Mat*_*lin 7

从可移植性的角度来看,向int转换指针是非常糟糕的.int的大小由编译器和体系结构的混合定义.这就是创建stdint.h标头的原因,允许您明确说明您在具有许多不同字长的许多不同平台上使用的类型的大小.

你最好不要转换为uintptr_t或intptr_t(来自stdint.h,并选择最符合你需要的签名的那个).


sil*_*cle 2

您必须手动编辑这些文件,以便将它们替换为不太可能有错误且不可移植的代码。