我有一个可以在32位计算机上编译和运行的软件包。我现在正试图让它在64位机器上编译并发现以下错误 -
error: cast from ‘void*’ to ‘int’ loses precision
是否有编译器标志来抑制这些错误?或者我是否必须手动编辑这些文件以避免这些演员表?
答案 0 :(得分:50)
问题在于,在32位中, int (这是一个32位整数)将保存指针值。
当你移动到64位时,你不能再将指针存储在int中 - 它不足以容纳64位指针。 intptr_t类型就是为此设计的。
答案 1 :(得分:23)
您的代码已损坏。忽略编译器给你的警告不会破坏它。
当您尝试将64位宽指针存储到32位整数时,您会认为会发生什么?一半的数据将被丢弃。我无法想象很多情况下这是正确的事情,或者它不会导致错误。
修复您的代码。或者保持代码当前工作的32位平台。
如果您的编译器定义了intptr_t
或uintptr_t
,请使用它们,因为它们是保证足够大的整数类型来存储指针。
如果这些类型不可用,size_t
或ptrdiff_t
也足以在大多数(并非所有)平台上保留指针。或者使用long
(通常在GCC编译器上的64位平台上为64位)或long long
(C99类型,大多数但不是所有编译器都支持C ++)或其他一些实现-defined整数类型,在64位平台上至少为64位宽。
答案 2 :(得分:13)
我的猜测是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的地址,将地址转换为所需数据类型的指针,然后跟随指针。
答案 3 :(得分:11)
出于某种原因,这是一个错误:int
只是您计算机上void*
的一半,因此您无法在void*
中存储int
。你会松开指针的一半,当程序稍后试图再次将指针从int
中取出时,它将无法获得任何有用的东西。
即使编译器不会出错,代码也很可能无效。需要更改代码并进行审核以获得64位兼容性。
答案 4 :(得分:7)
从可移植性的角度来看,向int转换指针是非常糟糕的。 int的大小由编译器和体系结构的混合定义。这就是创建stdint.h标头的原因,允许您明确说明您在许多不同平台上使用的类型的大小。
最好不要转换为uintptr_t或intptr_t(来自stdint.h,并选择最符合你需要的签名的那个)。
答案 5 :(得分:4)
您可以尝试使用intptr_t
来获得最佳的可移植性,而不是需要指针强制转换的int,例如回调。
答案 6 :(得分:4)
您不希望抑制这些错误,因为它们很可能表明代码逻辑存在问题。
如果你压制错误,这甚至可以工作一段时间。当指针指向前4 GB中的地址时,高32位将为0并且您不会丢失任何数据。但是一旦你得到一个地址> 4GB,你的代码将“神秘地”开始工作。
你应该做的是修改任何可以保存intptr_t指针的int。
答案 7 :(得分:3)
您必须手动编辑这些文件,以便用不太可能错误且不可移植的代码替换它们。
答案 8 :(得分:2)
抑制警告是一个坏主意,但可能是使用64位整数的编译器标志,具体取决于您的编译器和体系结构,这是一种解决问题的安全方法(当然假设代码也不假设整数是32位)。对于gcc,标志是-m64。
我想,最好的答案仍然是修复代码,但如果它是传统的第三方代码并且这些警告很猖獗,我不能认为这种重构是非常有效地利用你的时间。但是,绝对不要在任何新代码中转换为int的指针。
答案 9 :(得分:2)
根据当前的C ++标准定义,没有保证保存指针的整数类型。有些平台会有一个intptr_t,但这不是C ++的标准功能。从根本上说,将指针的位视为整数并不是一件容易的事情(尽管它可以在许多平台上工作)。
如果转换的原因是使指针不透明,那么void *已经实现了这一点,因此代码可以使用void *而不是int。 typedef可能会使代码
更好一些typedef void * handle_t;
如果转换的原因是使用字节粒度进行指针运算,那么最好的方法可能是转换为(char const *)并使用它进行数学运算。
如果转换的原因是为了实现与某些现有库(可能是较旧的回调接口)的兼容性而无法修改,那么我认为您需要查看该库的文档。如果库能够支持您所需的功能(即使在64位平台上),那么其文档可能会解决预期的解决方案。
答案 10 :(得分:1)
我遇到了类似的问题。我用以下方式解决了它:
#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中的编译器选项。
答案 11 :(得分:1)
有时想要将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);