在64位机器上编译32位代码时,应该如何处理“从void *'强制转换为”int“会失去精度?

我有一个在32位机器上编译和正常工作的软件包。 我现在试图让它在64位机器上编译,并find以下错误 –

error: cast from 'void*' to 'int' loses precision 

是否有一个编译器标志来抑制这些错误? 还是我必须手动编辑这些文件,以避免这些强制转换?

Solutions Collecting From Web of "在64位机器上编译32位代码时,应该如何处理“从void *'强制转换为”int“会失去精度?"

问题是,在32位,一个int (这是一个32位整数)将持有一个指针值。

当你移动到64位,你不能再存储一个指针在一个int – 它不够大,以容纳一个64位指针。 intptr_t类型是为此设计的。

你的代码坏了。 忽略编译器给你的警告,它不会被打破。

当你试图将一个64位宽的指针存储到一个32位的整数中时,你会怎么想呢? 你的一半数据将被扔掉。 我无法想象很多情况下,这是正确的事情,或者它不会导致错误。

修复你的代码。 或者留在代码当前工作的32位平台上。

如果你的编译器定义了intptr_t或者uintptr_t ,那就使用它们,因为它们是保证足够大的整数类型来存储一个指针。

如果这些类型不可用, size_tptrdiff_t也足够大,以在大多数 (不是全部)平台上保存指针。 或者使用long (在GCC编译器上通常是64位平台上的64位)或long long (C ++类型,大多数(但不是全部编译器)在C ++中支持的类型)或者其他一些实现定义的整型在64位平台上至少有64位宽。

我的猜测是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 

编译器不喜欢那最后一行。

我不会考虑以这种方式滥用虚空是否正确或错误。 如果你真的想愚弄编译器,下面的技术似乎工作,甚至用-Wall:

 int i2 = *((int*)&v); 

这里取v的地址,将地址转换成你想要的数据类型的指针,然后跟随指针。

这是一个错误,原因是: int在你的机器上只有void*一半,因此你不能只在int存储一个void* 。 你将失去一半的指针,当程序稍后再次尝试从那个int取出指针时,它将不会得到任何有用的东西。

即使编译器不会给出错误代码最有可能不会工作。 该代码需要改变和审查64位兼容性。

从可移植性的角度来看,将一个指针指向一个int是非常可怕的。 int的大小由编译器和体系结构的混合来定义。 这就是为什么stdint.h头文件被创建的原因,允许你在许多不同的平台上用不同的字大小明确地说明你正在使用的类型的大小。

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

您可以尝试使用intptr_t来获得最佳的可移植性,而不是使用指针强制转换的int,如回调。

你不想抑制这些错误,因为它们很可能是指示代码逻辑的一个问题。

如果你压制了这个错误,那么这个问题甚至可能会持续一段时间。 当指针指向前4 GB中的地址时,高32位将为0,并且不会丢失任何数据。 但是一旦你的地址> 4GB,你的代码就会“神秘”地开始工作。

你应该做的是修改任何可以容纳intptr_t指针的int。

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

抑制警告是一个坏主意,但可能有一个编译器标志使用64位整数,这取决于您的编译器和体系结构,这是一个安全的方法来解决这个问题(当然假设代码也没有假设整数是32位)。 对于gcc,标志是-m64。

我想最好的答案仍然是修复代码,但是如果它是传统的第三方代码,并且这些警告是猖獗的,我不能看到这个重构是非常有效地利用你的时间。 但是,绝对不要在任何新代码中投入指针。

正如现在的C ++标准所定义的那样,没有保证指针的整数类型。 一些平台将有一个intptr_t,但这不是C ++的标准功能。 从根本上说,把指针的位看作是一个整数是不是一个可移植的事情(尽管它可以在许多平台上工作)。

如果演员的原因是使指针不透明,那么void *已经实现了这一点,所以代码可以使用void *而不是int。 typedef可能会使代码更好一些

 typedef void * handle_t; 

如果转换的原因是用字节粒度进行指针运算,那么最好的办法是将其转换为(char const *),然后用这个数学运算。

如果演员的原因是为了与一些现有的库(也许是一个旧的回调接口)无法修改的兼容性,那么我认为你需要查看该库的文档。 如果库能够支持所需的功能(即使是在64位平台上),则其文档可能会解决预期的解决方案。

我面临类似的问题。 我用下面的方法解决了它:

  #ifdef 64BIT typedef uint64_t tulong; #else typedef uint32_t tulong; #endif void * ptr = NULL; //Whatever you want to keep it. int i; i = (int)(tulong)ptr; 

我认为,问题是类型化一个指向较短数据类型的指针。 但是对于更大的类型int ,它工作正常。

我将这个问题从类型转换为long类型的指针转​​换为64位整型到32位整型,并且工作正常。 我仍然在GCC / Clang中寻找编译器选项。

有时候想把一个64位的项目分成2个32位的项目是明智的。 这是你如何做到这一点:

头文件:

 //You only need this if you haven't got a definition of UInt32 from somewhere else typedef unsigned int UInt32; //x, when cast, points to the lower 32 bits #define LO_32(x) (*( (UInt32 *) &x)) //address like an array to get to the higher bits (which are in position 1) #define HI_32(x) (*( ( (UInt32 *) &x) + 1)) 

源文件:

 //Wherever your pointer points to void *ptr = PTR_LOCATION //32-bit UInt containing the upper bits UInt32 upper_half = HI_32(ptr); //32-bit UInt containing the lower bits UInt32 lower_half = LO_32(ptr);