C++ 在 64 位机器上编译 32 位代码时,我应该如何处理“从‘void*’转换到‘int’失去精度”?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2024895/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 21:51:50  来源:igfitidea点击:

How should I handle "cast from ‘void*’ to ‘int’ loses precision" when compiling 32-bit code on 64-bit machine?

c++linuxportability32bit-64bit

提问by badkya

I have a package that compiles and works fine on a 32-bit machine. I am now trying to get it to compile on a 64-bit machine and find the following error-

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

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

Is there a compiler flag to suppress these errors? or do I have to manually edit these files to avoid these casts?

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

回答by Reed Copsey

The issue is that, in 32bits, an int(which is a 32bit integer) will hold a pointer value.

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

When you move to 64bit, you can no longer store a pointer in an int - it isn't large enough to hold a 64bit pointer. The intptr_ttype is designed for this.

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

回答by jalf

Your code is broken. It won't become any less broken by ignoring the warnings the compiler gives you.

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

What do you thinkwill happen when you try to store a 64-bit wide pointer into a 32-bit integer? Half your data will get thrown away. I can't imagine many cases where that is the correct thing to do, or where it won't cause errors.

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

Fix your code. Or stay on the 32-bit platform that the code currently works on.

修复您的代码。或者留在代码当前运行的 32 位平台上。

If your compiler defines intptr_tor uintptr_t, use those, as they are integer types guaranteed to be large enough to store a pointer.

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

If those types are not available, size_tor ptrdiff_tare also large enough to hold a pointer on most(not all) platforms. Or use long(is typically 64-bit on 64-bit platforms on the GCC compiler) or long long(a C99 types which most, but not all compilers, support in C++), or some other implementation-defined integral type that is at least 64 bits wide on a 64-bit platform.

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

回答by erco

My guess is OP's situation is a void* is being used as general storage for an int, where the void* is larger than the int. So eg:

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

Compiler doesn't like that last line.

编译器不喜欢最后一行。

I'm not going to weigh in on whether it's right or wrong to abuse a void* this way. If you really want to fool the compiler, the following technique seems to work, even with -Wall:

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

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

Here it takes the address of v, converts the address to a pointer of the datatype you want, then follows the pointer.

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

回答by sth

It's an error for a reason: intis only half as big as void*on your machine, so you can't just store a void*in an int. You would loose half of the pointer and when the program later tries to get the pointer out of that intagain, it won't get anything useful.

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

Even if the compiler wouldn't give an error the code most likely wouldn't work. The code needs to be changed and reviewed for 64bit compatibility.

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

回答by Matthew Iselin

Casting a pointer to an int is horrible from a portability perspective. The size of int is defined by the mix of compiler and architecture. This is why the stdint.h header was created, to allow you to explicitly state the size of the type you're using across many different platforms with many different word sizes.

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

You'd be better off casting to a uintptr_t or intptr_t (from stdint.h, and choose the one that best matches the signedness you need).

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

回答by LiraNuna

You can try to use intptr_tfor best portability instead of int where pointer casts are required, such as callbacks.

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

回答by R Samuel Klatchko

You do not want to suppress these errors because most likely, they are indicating a problem with the code logic.

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

If you suppresses the errors, this could even work for a while. While the pointer points to an address in the first 4 GB, the upper 32 bits will be 0 and you won't lose any data. But once you get an address > 4GB, your code will start 'mysteriously' not working.

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

What you should do is modify any int that can hold a pointer to intptr_t.

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

回答by silentbicycle

You have to manually edit those files in order to replace them with code that isn't likely to be buggy and nonportable.

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

回答by user168715

Suppressing the warnings are a bad idea, but there maybe a compiler flag to use 64-bit ints, depending on your compiler and architecture, and this is a safe way to fix the problem (assuming of course that the code didn't also assume ints are 32-bit). For gcc, the flag is -m64.

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

The best answer is still to fix the code, I suppose, but if it's legacy third-party code and these warnings are rampant, I can't see this refactoring as being a very efficient use of your time. Definitely don't cast pointers to ints in any of your new code, though.

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

回答by nobar

As defined by the current C++ standard, there is no integer type which is guaranteed to hold a pointer. Some platforms will have an intptr_t, but this is not a standard feature of C++. Fundamentally, treating the bits of a pointer as if they were an integer is not a portable thing to do (although it can be made to work on many platforms).

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

If the reason for the cast is to make the pointer opaque, then void* already achieves this, so the code could use void* instead of int. A typedef might make this a little nicer in the code

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

typedef void * handle_t;

If the reason for the cast is to do pointer arithmetic with byte granularity, then the best way is probably to cast to a (char const *) and do the math with that.

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

If the reason for the cast is to achieve compatibility with some existing library (perhaps an older callback interface) which cannot be modified, then I think you need to review the documentation for that library. If the library is capable of supporting the functionality that you require (even on a 64-bit platform), then its documentation may address the intended solution.

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