首页 > 解决方案 > 取消引用 void * 就像 (int) - 标准做法?

问题描述

我试图打印线程的返回值,发现我仍然对双空指针的概念感到困惑。

我的理解是 void* 是指向可以通过适当的强制转换取消引用的任何数据类型的指针,但除此之外,引用的“级别”与常规类型指针一样被保留(即,您不能期望获得与你**(int **)depth2只需要取消引用一次就好了*depth2。)。

然而,在我为我的线程返回打印拼凑起来的代码(下面)中,当我只是将它强制转换为(int)时,似乎我根本没有取消引用void 指针。这是将地址用作值的情况吗?如果是这样,这是从线程返回的正常方式吗?否则,我错过了什么?

(我知道在线程内操作数据的更安全的方法可能是调用者级别的存储,但我对这种情况以及我不了解 void 指针的原因很感兴趣。)

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

void *myThread(void *arg)
{
    return (void *)42;
}

int main()
{
    pthread_t tid;
    void *res;                                        // res is itself a void *

    pthread_create(&tid, NULL, myThread, NULL);
    pthread_join(tid, &res);                          // i pass its address, so void** now
    printf(" %d \n", (int)res);                       // how come am i able to just use it as plain int?

    return 0;
}

标签: cmultithreadingvoid

解决方案


首先, 的目的pthread_join()是通过它的第二个参数更新void * 给定的,以便获得线程函数 (a void *) 的结果。
当您需要更新时,参数中的intas是要更新的地址:an 。 出于同样的原因,您可以通过提供 a 来更新 a 。scanf("%d", &my_var);intint *
void *void **

在您的示例的具体情况下,我们不会 void *以正常方式使用返回的:这是一个技巧!
由于指针可以被认为是一个大整数,对很长的一行中的字节进行计数,所以诀窍是假设这个指针可以简单地存储一个不引用任何内存位置的整数值。

在您的示例中,返回(void *)42, 相当于说“您会在地址 42 找到有趣的东西”。
但是这个地址从来没有被放置过!
这是一个问题吗?不,只要没有人试图取消引用此指针以检索地址 42 处的内容。

pthread_join()执行后,变量已res更新并包含返回的void *: 42 在这种情况下。
我们在这里通过假设存储在此指针中的信息不引用内存位置而是一个简单的整数来执行反向技巧。

它有效,但这很丑陋!
主要优点是您避免了 malloc()/free() 的昂贵成本

void *myThread(void *arg)
{
  int *result=malloc(sizeof(int));
  *result=42;
  return result;
}

...
int *res;
pthread_join(tid, &res);
int result=*res; // obtain 42
free(res);

避免这种成本的更好解决方案是使用线程函数的参数。

void *myThread(void *arg)
{
  int *result=arg;
  *result=42;
  return NULL;
}

...
int expected_result;
pthread_create(&tid, NULL, myThread, &expected_result);
pthread_join(tid, NULL);
// here expected_result has the value 42

推荐阅读