为什么这个转换为void指针有效?

时间:2011-07-31 12:47:56

标签: c pointers casting void

我正在调试一本书中的程序。该程序似乎有效,但我不明白我在下面评论的一行。

#include <pthread.h>
#include <stdio.h>
/* Compute successive prime numbers (very inefficiently). Return the
Nth prime number, where N is the value pointed to by *ARG. */
void* compute_prime (void* arg)
{
int candidate = 2;
int n = *((int*) arg);
while (1) {
int factor;
int is_prime = 1;
/* Test primality by successive division. */
for (factor = 2; factor < candidate; ++factor)
if (candidate % factor == 0) {
is_prime = 0;
break;
}
/* Is this the prime number we’re looking for? */
if (is_prime) {
if (--n == 0)
/* Return the desired prime number as the thread return value. */
return (void*) candidate;    // why is this casting valid? (candidate is not even a pointer)
}
++candidate;

}
return NULL;
}
int main ()
{
pthread_t thread;
int which_prime = 5000;
int prime;
/* Start the computing thread, up to the 5,000th prime number. */
pthread_create (&thread, NULL, &compute_prime, &which_prime);
/* Do some other work here... */
/* Wait for the prime number thread to complete, and get the result. */
pthread_join (thread, (void*) &prime);
/* Print the largest prime it computed. */
printf(“The %dth prime number is %d.\n”, which_prime, prime);
return 0;
}

3 个答案:

答案 0 :(得分:5)

无效。如果sizeof(int) == sizeof(void *)发生在许多系统上,它就会发生。

只保证void *能够保存指向数据对象的指针。

这是关于这个主题的C FAQ

  

如何将整数转换为指针和从指针转换? 我可以暂时吗?   将整数填入指针,反之亦然?

     

指针到整数和整数到指针的转换是   实现定义(见问题11.33),不再存在   任何保证指针可以转换为整数和返回,   没有改变

     

强制指针指向整数或整数成指针,从来没有   一直很好的做法

答案 1 :(得分:1)

“有效”是什么意思?

您明确要求演员表,语言或编译器不会阻止您。它是否有用是完全不同的事情。实际上,正如你所说,candidate不是一个指针,它并没有指向任何有用的东西。返回值的接收者必须知道如何处理它(例如,将其强制转换回int,尽管不能保证这会使您返回原始值。)

如果您从不需要该值,则可以返回0。只是pthread_create期望作为参数的类型为void*(*)(void*)的函数指针,因此您的函数必须返回void*。如果您不需要它,您可以忽略它并返回任何旧值。

(在其他情况下,你的线程函数可能选择了malloc()一些内存,用结果数据填充它并返回指向该地址的指针,这就是void*在某种意义上的原因“最常见的“C函数的返回类型,需要尽可能灵活,而不知道它将如何使用。”

答案 2 :(得分:1)

虽然其他人认为C离开了此实现定义的结果是正确的,但您的代码(使用pthreads)依赖于POSIX,这需要一个内存模型,编译器必须将其从它打破你正在做的事情的方式。此外,所有真实的POSIX实现都是ILP32或LP64,这意味着int的任何值都适合指针。

虽然从正式角度看“丑陋”,但使用int - to - void *使用线程参数或返回值来传递小整数数据通常是两个邪恶中较小的一个,另一个选择在一个线程中为malloc(sizeof(int))而在另一个线程中为free,这不仅会从根本上增加显着的成本,而且在某些分配器上也可能是病态上不好的,这些分配器仅针对分配线程和释放线程是相同。

一种方法可以避免这两种弊端:如果线程的创建者会坚持一段时间并最终调用pthread_join,则可以将新线程指针传递给创建者堆栈上的数据对象或创建者另外拥有的内存中的数据对象。然后,新线程可以在结束之前将其结果写入此位置。