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

时间:2009-10-28 22:04:06

标签: c++ casting void-pointers

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

int x = (int)arg;

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

file.cpp:233: error: cast from 'void*' to 'int' loses precision

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

18 个答案:

答案 0 :(得分:61)

您可以将其转换为intptr_t类型。它是int类型,保证足够大以包含指针。使用#include <cstdint>进行定义。

答案 1 :(得分:26)

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

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

int x = *((int*)(&arg));

这适用于GCC4。

最好的方法是,如果可以的话,不要进行这样的转换,相反,如果必须为指针和int共享相同的内存地址(例如,为了保存RAM),请使用union,并确保,如果mem只有当您知道它最后设置为int时,才将地址视为int。

答案 2 :(得分:11)

在一般情况下,没有正确的方法将其强制转换为int。 C99标准库提供了intptr_tuintptr_t typedef,它们应该在需要执行此类转换时使用。如果您的标准库(即使它不是C99)恰好提供这些类型 - 请使用它们。如果没有,请检查平台上的指针大小,自己定义这些typedef并使用它们。

答案 3 :(得分:8)

而不是:

int x = (int)arg;

使用:

int x = (long)arg;

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

答案 4 :(得分:7)

将指针转换为void *并返回有效使用reinterpret_cast&lt;&gt;。所以你可以这样做:

pthread_create(&thread, NULL, myFcn, new int(5)); // implicit cast to void* from int*

然后在myFcn:

void* myFcn(void* arg)
{
    int*  data = reinterpret_cast<int*>(arg);
    int   x    = *data;
    delete data;

注意:正如sbi指出的那样,这需要对OP调用进行更改以创建线程。

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

因此,结果可能不太容易错误地生成指针并且使用它。 记得在使用后删除指针,这样我们就不会泄漏。

答案 5 :(得分:4)

而不是使用长投射,你应该施放到size_t。

int val =(int)((size_t)arg);

答案 6 :(得分:3)

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

答案 7 :(得分:2)

我也遇到了这个问题。

ids [i] =(int)arg; //这里发生错误=&gt;我将此更改为以下内容。

ids [i] =(uintptr_t)arg;

然后我可以继续编译。也许你也可以尝试一下。

答案 8 :(得分:1)

没有“正确”的方法将64位指针存储在32位整数中。问题不在于强制转换,而是目标类型丢失指针的一半。存储在int内的32个剩余比特不足以重建指向线程函数的指针。大多数答案只是试图从论证中提取32个无用的位。

正如Ferruccio所说,int必须替换为intptr_t才能使程序有意义。

答案 9 :(得分:1)

我会创建一个结构并将其作为void *传递给pthread_create

struct threadArg {
    int intData;
    long longData;
    etc...
};


threadArg thrArg;
thrArg.intData = 4;
...
pthread_create(&thread, NULL, myFcn, (void*)(threadArg*)&thrArg);


void* myFcn(void* arg)
{
    threadArg* pThrArg = (threadArg*)arg;
    int computeSomething = pThrArg->intData;
    ...
}

请记住 thrArg 应该存在,直到 myFcn()使用它。

答案 10 :(得分:1)

最安全的方式:

static_cast<int>(reinterpret_cast<long>(void * your_variable));

long保证Linux在任何机器上的指针大小。 Windows在64位上也只有32位长。因此,您需要在Windows中为64位将其更改为long long而不是long。 因此,reinterpret_cast已将其转换为long类型,然后static_cast安全地将long转换为int,如果您准备好,请截断数据。

答案 11 :(得分:1)

如果你像这样调用你的线程创建函数

pthread_create(&thread, NULL, myFcn, reinterpret_cast<void*>(5));

然后void*到达myFcn内的int具有您放入其中的int myData = reinterpret_cast<int>(arg); 的值。所以你知道你可以像这样把它丢回来

myFcn

即使编译器不知道你只是将pthread_createsizeof(void*)>=sizeof(int)一起传递给整数。

修改

正如马丁所指出的,这假设{{1}}。如果您的代码有机会被移植到某个不能保持的平台,那么这将无效。

答案 12 :(得分:0)

//new_fd is a int
pthread_create(&threads[threads_in_use] , NULL, accept_request, (void*)((long)new_fd));

//inside the method I then have
int client;
client = (long)new_fd;

希望这有帮助

答案 13 :(得分:0)

你可能想要的是

int x = reinterpret_cast<int>(arg);

这允许您将void *重新解释为int

答案 14 :(得分:0)

就我而言,我使用的是32位值,需要传递给OpenGL函数,作为void *表示缓冲区的偏移量。

您不能只将32位变量强制转换为指针,因为64位计算机上的指针长度是其两倍。指针的一半将是垃圾。你需要传递一个实际的指针。

这将为您提供一个来自32位偏移的指针:

int32 nOffset   = 762;       // random offset
char * pOffset  = NULL;      // pointer to hold offset
pOffset         += nOffset;  // this will now hold the value of 762 correctly
glVertexAttribPointer(binding, nStep, glType, glTrueFalse, VertSize(), pOffset);

答案 15 :(得分:0)

不要将您的int作为void*传递,将int*传递给int,这样您就可以将void*转换为int*并且将解除引用的指针复制到int

int x = *static_cast<int*>(arg);

答案 16 :(得分:0)

函数指针与void *(以及任何其他非函数指针)

不兼容

答案 17 :(得分:-3)

这样做是因为您将64位指针转换为32位整数,因此您会丢失信息。

你可以使用64位整数代替howerver我通常使用一个带有正确原型的函数,然后我转换函数类型: 例如

void thread_func(int arg){
...
}

我创建了这样的线程:

pthread_create(&tid, NULL, (void*(*)(void*))thread_func, (void*)arg);