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

发布于 2024-11-26 23:13:51 字数 1263 浏览 1 评论 0原文

我正在调试书上的程序。该程序似乎可以工作,但我不明白我在下面评论的一行。

#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;
}

I'm debugging a program from a book. The program appears to work but I do not understand one line which I comment below.

#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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

不顾 2024-12-03 23:13:51

这是无效的。如果sizeof(int) == sizeof(void *),它恰好可以工作,这在许多系统上都会发生。

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

这是关于该主题的 C 常见问题解答

整数如何与指针相互转换? 我可以暂时
将整数填充到指针
,或反之亦然?

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

将指针强制转换为整数,或将整数强制转换为指针,从来没有
很好的做法

It's not valid. It simply happens to work if sizeof(int) == sizeof(void *), which happens on many systems.

A void * is only guaranteed to be able to hold pointers to data objects.

Here is a C FAQ on the subject.

How are integers converted to and from pointers? Can I temporarily
stuff an integer into a pointer
, or vice versa?

Pointer-to-integer and integer-to-pointer conversions are
implementation-defined (see question 11.33), and there is no longer
any guarantee that pointers can be converted to integers and back,
without change

Forcing pointers into integers, or integers into pointers, has never
been good practice

寒江雪… 2024-12-03 23:13:51

你所说的“有效”是什么意思?

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

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

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

What do you mean by "valid"?

You're explicitly requesting a cast, and the language or the compiler won't stop you. Whether it's useful is an entirely different matter. Indeed, as you say, candidate isn't a pointer and it's not pointing to anything useful. The recipient of the return value will have to know what to do with it (e.g. cast it back to int, though it's not guaranteed that that gives you back the original value).

If you never need the value, you might just return 0. It's simply that pthread_create expects as an argument a function pointer of type void*(*)(void*), so your function has to return a void*. If you don't need it, you can ignore it and just return any old value.

(In other situations, your thread function might have chosen to malloc() some memory, fill it with result data and return a pointer to that address, which is why void* is in some sense the "most general" return type for a C function that needs to be as flexible as possible without knowing how it's going to be used.)

古镇旧梦 2024-12-03 23:13:51

虽然其他人认为 C 保留此转换的结果实现定义是正确的,但您的代码(使用 pthreads)依赖于 POSIX,这需要一个编译器必须不遗余力地使用内存模型打破你正在做的事情。此外,所有现实世界的 POSIX 实现都是 ILP32 或 LP64,这意味着 int 的任何值都适合指针。

虽然从正式的角度来看“丑陋”,但使用 int-to-void * 转换与线程参数或返回值来传递小整数数据通常是两害相权取其轻,另一种选择是一个线程中的 malloc(sizeof(int)) 和另一个线程中的 free,这不仅从根本上增加了显着的成本,而且还可能对一些分配器仅针对以下情况进行调整分配线程和释放线程是相同的。

可以避免这两害的一种方法是:如果线程的创建者会停留一段时间并最终调用 pthread_join,您可以向新线程传递一个指向创建者堆栈上或创建者拥有的内存中的数据对象。然后,新线程可以在终止之前将其结果写入此位置。

While others are right that C leaves the results of this cast implementation-defined, your code (using pthreads) depends on POSIX, which requires a memory model where a compiler would have to go out of its way to break what you're doing. Also all real-world POSIX implementations are ILP32 or LP64 meaning that any value of int will fit in a pointer.

While "ugly" from a formal standpoint, using int-to-void * casts with the thread argument or return value to pass small integer data is usually the lesser of two evils, the other choice being malloc(sizeof(int)) in one thread and free in the other, which not only fundamentally adds significant costs, but also can be pathologically bad on some allocators tuned only for the case where the allocating thread and freeing thread are the same.

One way you can avoid both evils: if the creator of the thread will be sticking around for a while and eventually calling pthread_join, you could pass the new thread a pointer to a data object on the creator's stack or in memory otherwise owned by the creator. The new thread can then write its result to this location before it terminates.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文