34

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

 error: cast from ‘void*’ to ‘int’ loses precision

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

4

12 回答 12

50

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

当您移至 64 位时,您不能再将指针存储在 int 中 - 它不足以容纳 64 位指针。intptr_t类型就是为此而设计的。

于 2010-01-08T01:38:37.830 回答
23

你的代码坏了。通过忽略编译器给你的警告,它不会变得更糟。

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

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

如果您的编译器定义了intptr_tor uintptr_t,请使用它们,因为它们是保证足够大以存储指针的整数类型。

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

于 2010-01-08T03:17:24.073 回答
15

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

编译器不喜欢最后一行。

我不会权衡以这种方式滥用 void* 是对还是错。如果您真的想欺骗编译器,即使使用 -Wall,以下技术似乎也有效:

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

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

于 2010-09-23T05:55:03.017 回答
11

这是一个错误是有原因的:int只有void*你机器上的一半大,所以你不能只将 a 存储void*int. 你会丢失一半的指针,当程序稍后试图再次从中取出指针时int,它不会得到任何有用的东西。

即使编译器不会给出错误,代码也很可能无法工作。需要更改和审查代码以实现 64 位兼容性。

于 2010-01-08T01:41:12.847 回答
7

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

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

于 2010-01-08T01:37:26.990 回答
4

您可以尝试使用intptr_t最佳可移植性而不是 int 需要指针转换的地方,例如回调。

于 2010-01-08T01:38:07.393 回答
4

您不想抑制这些错误,因为它们很可能表明代码逻辑存在问题。

如果你抑制错误,这甚至可以工作一段时间。虽然指针指向前 4 GB 中的地址,但高 32 位将为 0,您不会丢失任何数据。但是一旦你得到一个大于 4GB 的地址,你的代码就会开始“神秘地”不起作用。

您应该做的是修改任何可以保存指向 intptr_t 的指针的 int。

于 2010-01-08T01:38:44.380 回答
2

按照当前 C++ 标准的定义,没有整数类型可以保证保存指针。一些平台会有一个 intptr_t,但这不是 C++ 的标准特性。从根本上说,将指针的位视为整数并不是一件可移植的事情(尽管它可以在许多平台上工作)。

如果强制转换的原因是使指针不透明,那么 void* 已经实现了这一点,因此代码可以使用 void* 而不是 int。typedef 可能会使代码中的这个更好一点

typedef void * handle_t;

如果强制转换的原因是使用字节粒度进行指针运算,那么最好的方法可能是强制转换为 (char const *) 并用它进行数学运算。

如果强制转换的原因是为了实现与某些无法修改的现有库(可能是较旧的回调接口)的兼容性,那么我认为您需要查看该库的文档。如果库能够支持您需要的功能(即使在 64 位平台上),那么它的文档可能会解决预期的解决方案。

于 2010-01-09T22:09:12.377 回答
2

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

于 2010-01-08T01:35:51.580 回答
2

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

我想,最好的答案仍然是修复代码,但如果它是遗留的第三方代码并且这些警告很猖獗,我认为这种重构不能非常有效地利用你的时间。不过,绝对不要在任何新代码中将指针转换为整数。

于 2010-01-08T03:06:36.823 回答
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); 
于 2014-07-09T16:11:32.387 回答
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;

我认为,问题在于将指针类型转换为较短的数据类型。但是对于更大的类型 to int,它工作正常。

我将此问题从将指针long类型转换为将 64 位整数类型转换为 32 位整数,并且效果很好。我仍在寻找 GCC/Clang 中的编译器选项。

于 2013-03-04T10:35:58.813 回答