我有一个带有原型的函数,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
投射这个的正确方法是什么?
我有一个带有原型的函数,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
投射这个的正确方法是什么?
您可以将其转换为intptr_t
类型。它是一种int
保证足够大以包含指针的类型。用来#include <cstdint>
定义它。
同样,以上所有答案都严重错过了重点。OP 想要将指针值转换为 int 值,相反,大多数答案都试图错误地将 arg 点的内容转换为 int 值。而且,其中大多数甚至无法在 gcc4 上运行。
正确的答案是,如果不介意丢失数据精度,
int x = *((int*)(&arg));
这适用于 GCC4。
最好的方法是,如果可以,不要进行这种转换,相反,如果必须为指针和 int 共享相同的内存地址(例如,为了节省 RAM),请使用 union,并确保是否处理了 mem 地址仅当您知道它最后设置为 int 时才作为 int。
代替:
int x = (int)arg;
利用:
int x = (long)arg;
在大多数平台上,指针和 long 的大小相同,但 int 和指针在 64 位平台上通常大小不同。如果将 ( void*
) 转换为 ( long
) 不会丢失精度,那么通过将 ( long
) 分配给 ( int
),它会正确截断数字以适合。
int
在一般情况下,没有适当的方法可以将其转换为。C99 标准库提供intptr_t
和uintptr_t
typedef,应该在需要执行此类转换时使用。如果您的标准库(即使它不是 C99)碰巧提供了这些类型 - 请使用它们。如果没有,请检查您平台上的指针大小,自己定义这些类型定义并使用它们。
将指针转换为 void* 并返回是对 reinterpret_cast<> 的有效使用。所以你可以这样做:
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* 并再次返回。
因此,结果是动态生成指针并使用它可能不太容易出错。记住在使用后删除指针,这样我们就不会泄漏。
而不是使用long
强制转换,您应该强制转换为size_t
.
int val= (int)((size_t)arg);
我也遇到这个问题。
ids[i] = (int) arg; // error occur here => I change this to below.
ids[i] = (uintptr_t) arg;
然后我可以继续编译。也许你也可以试试这个。
正确的方法是将其转换为另一个pointer type
. 将 a 转换void*
为 anint
是不可移植的方式,可能有效也可能无效!如果您需要保留返回的地址,只需将其保留为void*
.
最安全的方式:
static_cast<int>(reinterpret_cast<long>(void * your_variable));
long
保证任何机器上 Linux 上的指针大小。Windows 也只有 64 位的 32 位。因此,您需要将其更改为long long
而不是long
在 windows 中为 64 位。因此reinterpret_cast
,已将其转换为long
type ,然后static_cast
安全地转换long
为int
,如果您准备好截断数据。
没有“正确”的方式将 64 位指针存储在 32 位整数中。问题不在于强制转换,而在于目标类型丢失了一半的指针。内部存储的 32 个剩余位int
不足以重建指向线程函数的指针。大多数答案只是试图从论点中提取 32 个无用的位。
正如Ferruccio所说,必须将 int 替换为intptr_t
才能使程序有意义。
如果你像这样调用你的线程创建函数
pthread_create(&thread, NULL, myFcn, reinterpret_cast<void*>(5));
然后void*
到达的内部myFcn
具有int
您放入其中的值。所以你知道你可以像这样把它扔回去
int myData = reinterpret_cast<int>(arg);
即使编译器不知道您只与整数一起传递myFcn
给pthread_create
。
编辑:
正如 Martin 所指出的,这假定sizeof(void*)>=sizeof(int)
. 如果您的代码有机会被移植到某些平台上,而这并不适用,那么这将行不通。
我会创建一个结构并将其作为 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()使用它。
你可能想要的是
int x = reinterpret_cast<int>(arg);
这允许您将 重新解释void *
为int
.
在我的例子中,我使用了一个 32 位的值,该值需要作为 void * 传递给 OpenGL 函数,表示缓冲区的偏移量。
您不能只将 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);
不要将您的 int 作为 avoid*
传递,将 a 传递int*
给您的int
,因此您可以将 the 强制void*
转换为 anint*
并将取消引用的指针复制到您的int
.
int x = *static_cast<int*>(arg);
//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;
希望这可以帮助
函数指针与 void* (以及任何其他非函数指针)不兼容
之所以这样做,是因为您将 64 位指针转换为 32 位整数,因此您会丢失信息。
您可以使用 64 位整数来代替,但是我通常使用具有正确原型的函数并转换函数类型:例如。
void thread_func(int arg){
...
}
我创建这样的线程:
pthread_create(&tid, NULL, (void*(*)(void*))thread_func, (void*)arg);