前言
这种方式是我在研究多线程编程的过程中发现的一种理解方式,虽然并不官方,但是便于理解指针的传递过程。
请看一看下面代码:
void *function(void* arg){
int *return_data = (int*)arg;
(*return_data)+=10;
return (void*)return_data;
}
int main(){
int a=10;
pthread_t t1;
pthread_create(&t1,NULL,function,(void*)&a);
int *result;
pthread_join(t1,(void**)&result);
printf("%d\n",*result);
}
不过本次讨论的并非是线程的创建,而是pthread_join(t1,(void**)&result);这一行代码。
pthread_join
这个函数的函数原型是:int pthread_join(pthread_t __th, void **__thread_return),第二个参数是二级指针,使用二级指针的意义是为了在这个函数中能修改外部的值。
假设这个函数不使用二级指针,那么外部传入的值则在函数内部是副本,副本的修改不会影响到外界的值。
虚无指针理论
首先要明确一点,一个变量存在两个意义,一个是它的值,另一个是它的地址。
int *a = &b;
这样一个表达式,可以知道&b的意思其实就是一个a指针指向了b,那么以此为基础,来看一看(void**)&result这个表达式。
由前面的int *result可知,这个result变量是一个一级指针,那么&result就有点匪夷所思,如果加上(void**)就更加一团雾水,那么如果在此时引入“虚无指针”的概念,则会彻底解开谜团。
先说一说我对虚无指针的定义——一个没有实体,只存在逻辑的指针。所以这个指针只能存在于脑海中,因为它在现实中是不存在的。
理论结束,实践开始。
int** = &result,根据result是一级指针这一点,可以反推出它的虚无指针是二级指针,那么这个(void**)的强转也就变得清晰了,他实际上就是将虚无指针int**强转成了void**类型,然后传入函数phread_join
下面给出一个pthread_join的大致模型:
int pthread_join(pthread_t __th, void **__thread_return){
//....
*__thread_return = return_data;
//....
}
当传入的指针被解引用之后,就成为了一级指针(也就是result),这个一级指针能被线程函数的返回值赋值了,比如这里被赋值为return_data的地址。
然后函数结束,此时的result的虚无指针渡过了(void**)&的影响范围,这里就引入虚无指针的第二特点——虚无指针的作用周期只存在于当前正在使用的函数,作用域结束则会坍塌。
承接上文,虚无指针void**坍塌消失,result重新成为普通的int*,它的值存储的是return_data中存储的地址,所以printf("%d\n",*result);将地址解引用,得到return_data中的地址所指向的值。
