我一直在关注Mitchell,Oldham和Samuel的高级Linux编程。我在pthreads一节中看到过一些关于void指针和转换的东西让我很困惑。
将参数传递给pthread_create(),它们不会将指针强制转换为void指针,即使这是函数所期望的。
pthread_create( &thread, NULL, &compute_prime, &which_prime );
此处, which_prime 的类型为 int 。
但是使用pthread_join从线程返回一个值,他们将变量转换为void指针。
pthread_join( thread, (void*) &prime );
此处, prime 的类型为 int 。
为什么在第二个实例中完成转换而不在第一个实例中完成转换?
答案 0 :(得分:10)
第二个例子是一个很好的例子,说明为什么投射到void*
通常是一个错误。它应该是
void *primep = ′ // no cast needed
pthread_join(thread, &primep);
因为pthread_join
将void**
作为其第二个参数。 void*
仅确保错误通过编译器,因为void*
会自动转换为void**
。
所以,当做时,您需要转换为void*
或返回:
(u)intptr_t
); void*
(或采用不同类型的指针,并且void*
);这通常意味着函数采用可变数量的参数,例如printf
。答案 1 :(得分:9)
无需在C:
中转换为指向void
的指针
6.3.2.3指针
1 指向 void 的指针可以转换为指向任何不完整或对象的指针 类型。指向任何不完整或对象类型的指针可能会转换为指向 void 的指针 又回来了;结果应该等于原始指针。
唯一的例外是
"%p"
转化说明符打印指针时,因为它仅为void *
定义。intptr_t
或uintptr_t
复制回void *
。答案 2 :(得分:4)
在C中,隐式地从任何指针类型转换为void *,反之亦然。 在第二个例子中没有必要进行演员表。
(注意,在C ++中,任何指向void *的指针也是隐式执行的(函数指针和函数成员/方法指针除外,它们不能转换为void *),但是回退需要显式转换。)
答案 3 :(得分:2)
int pthread_join(pthread_t thread, void **retval);
因此,pthread_join
将pointer to void*
作为其第二个参数。这是因为,
在pthread_join中,您将获取传递给pthread_exit的地址 完成的线程。如果只传递一个普通指针,则传递给它 值,这样你就无法改变指向的位置。有能力去 更改传递给pthread_join的指针的值,它必须是 作为指针本身传递,即指向指针的指针。
现在,对于你的问题," 为什么在第二个实例中而不是在第一个实例中完成转换?"
在第一个实例中,即pthread_create
,它期望void*
作为其第四个参数。因此,传递&which_prime
将隐式转换为void*
。
在第二个例子中,即pthread_join
,它需要一个void**
,我们正在那里传递&prime
。所以,编译器会抱怨。因此,为了绕过该错误,作者传递void*
的演员表,该演员表将自动转换为void**
。
但这不是一个好的解决方案。
解决方案::
void* prime ; // make prime as void*
pthread_join( thread, &prime );
printf( "%" PRIxPTR "\n", (intptr_t)prime ) ;
// intptr_t instead of int to get an integer type
// that's the same size as a pointer
答案 4 :(得分:1)
我相信其他referenced中的相同代码questions。
第二个链接中的答案解释了:
它无效。如果sizeof(int)==,它恰好会起作用 sizeof(void *),发生在许多系统上。
void *仅保证能够保存指向数据的指针 对象。
这是关于这个主题的C FAQ。
引用文字:
如何将整数转换为指针和从指针转换?我可以暂时吗? 将整数填充到指针中,反之亦然?
指针到整数和整数到指针的转换是 实现定义(见问题11.33),不再存在 任何保证指针可以转换为整数和返回, 没有改变
强制指针指向整数或整数成指针,从来没有 一直很好的做法