错误:从'void*'转换为'int'会失去精度

Jos*_*oyd 59 c++ casting void-pointers

我有一个原型函数,void* myFcn(void* arg)用作pthread的起点.我需要将参数转换为int以供以后使用:

int x = (int)arg;
Run Code Online (Sandbox Code Playgroud)

编译器(GCC版本4.2.4)返回错误:

file.cpp:233: error: cast from 'void*' to 'int' loses precision
Run Code Online (Sandbox Code Playgroud)

投这个的正确方法是什么?

Fer*_*cio 62

您可以将其强制转换为intptr_t类型.它是一种int保证足够大以包含指针的类型.使用#include <cstdint>来定义它.

  • 不要忘记`#include <stdint.h>`来获取`intptr_t` typedef. (7认同)
  • `#include <inttypes.h>`.它包括stdint.h. (6认同)

onl*_*ker 29

同样,上面的所有答案都严重错过了这一点.OP想要将指针值转换为int值,相反,大多数答案,无论是哪种方式,都试图将arg点的内容错误地转换为int值.并且,其中大多数甚至不适用于gcc4.

正确答案是,如果不介意丢失数据精度,

int x = *((int*)(&arg));
Run Code Online (Sandbox Code Playgroud)

这适用于GCC4.

最好的方法是,如果一个人可以,不做这样的转换,相反,如果必须为指针和int共享相同的内存地址(例如,为了保存RAM),使用union,并确保,如果mem地址被处理只有当你知道它最后被设置为int时才作为int.

  • 这甚至不是"正确的答案".这根本不是转换.这是记忆重新解释 - 这是一种完全不可接受的方式来做OP正在尝试做的事情. (9认同)
  • 此方法不适用于64位Big Endian平台,因此不必要地破坏了可移植性. (5认同)
  • Uggh.可怕的解决方案.错误.这将返回指针的前32位,可能是顶部或底部,取决于大端与小端,正如注释#2所述.在最好的情况下,这将给出与原始代码相同的结果,没有任何优势,但在最坏的情况下,它将以多种灾难性方式失败(类型双关,字节序,效率低等) (5认同)
  • 这是错误的.不知道它如何积累了27个赞成票?!-1 (4认同)

AnT*_*AnT 11

int在一般情况下,没有适当的方法来演绎这一点.C99标准库提供intptr_tuintptr_t类型定义,它应该每当执行这样的铸造需要来将要使用的.如果您的标准库(即使它不是C99)恰好提供这些类型 - 请使用它们.如果没有,请检查平台上的指针大小,自己定义这些typedef并使用它们.


Jos*_*oyd 8

代替:

int x = (int)arg;
Run Code Online (Sandbox Code Playgroud)

使用:

int x = (long)arg;
Run Code Online (Sandbox Code Playgroud)

在大多数平台上,指针和长整数的大小相同,但是在64位平台上,整数和指针的大小通常不同.如果你将convert(void*)转换为(long)没有精度丢失,那么通过将(long)分配给(int),它会正确地截断数字以适应.

  • 在Windows 64上无效 - long仍为32位,但指针为64位. (13认同)
  • @Martin York:不,它不依赖于字节序。pointer&lt;-&gt;integer casts 中的映射是实现定义的,但目的是如果指针类型足够大并且没有强制对齐(`void*` 没有)那么往返转换整数到指针-to-integer 应该产生原始值。指针到整数到指针的往返行程相同。 (2认同)

Mar*_*ork 7

将指针转换为void*并返回是有效使用reinterpret_cast <>.所以你可以这样做:

pthread_create(&thread, NULL, myFcn, new int(5)); // implicit cast to void* from int*
Run Code Online (Sandbox Code Playgroud)

然后在myFcn中:

void* myFcn(void* arg)
{
    int*  data = reinterpret_cast<int*>(arg);
    int   x    = *data;
    delete data;
Run Code Online (Sandbox Code Playgroud)

注意:正如sbi所指出的,这需要在OP调用上进行更改以创建线程.

我试图强调的是,当你从一个平台移动到另一个平台时,从int转换到指针再返回可能会出现问题.但是,将指针转换为void*并再次返回可以得到很好的支持(无处不在).

因此,结果可能不太容易错误地生成指针并且使用它.记住在使用后删除指针,以便我们不泄漏.

  • 绝对没有保证sizeof(int)<= sizeof(void*).事实上,我知道几个系统不成立. (3认同)
  • 我所说的是使用new(5)而不是5更安全,并在另一端适当处理它. (2认同)

Geo*_*ter 6

而不是使用long强制转换,您应该强制转换为size_t.

int val= (int)((size_t)arg);
Run Code Online (Sandbox Code Playgroud)


Muh*_*Ali 5

我也遇到这个问题。

ids[i] = (int) arg; // error occur here => I change this to below.

ids[i] = (uintptr_t) arg;
Run Code Online (Sandbox Code Playgroud)

然后我可以继续编译。也许你也可以试试这个。


Ara*_*raK 3

正确的方法是将其投射到另一个pointer type. 将 a 转换void*为 anint是不可移植的方式,可能有效也可能无效!如果需要保留返回的地址,则保留为void*

  • AraK 是正确的,传递整数和指针不一定可以互换。他应该传递整数的地址,线程应该获取该地址,将其“static_cast”转换为“int*”,然后获取值。这必须在整数超出范围之前完成。 (2认同)