函数指针与指针函数:从pthread_create说起

Linux线程创建函数的定义是这样的:

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
					void *(*start_routine)(void *), void *arg);

其中的第三个参数void *(*start_routine)(void *)该如何理解?


一、函数指针与指针函数:

函数指针:

本质是指针,指向一个函数的指针。

用法:

int (*p)(int, int);  	//定义一个函数指针
int func(int a, int b) {
    
     }
p = &func;

指针函数:

本质是一个函数,函数的返回值是一个指针。

用法:

int *p(void) {
    
     
	int *addr = (int*)malloc(sizeof(int));
	return addr;
}
int main() {
    
    
	int *mem = p(void);
	return 0;
}

几点注意事项:

  1. 下面这种写法是绝对错误的:

    void (*p)(void) {
          
           }
    

    因为这是在定义一个函数指针,它只是一个指针,后面就不能有函数体。

  2. &func 与 func 的区别:

    函数名与对函数名取址有什么区别:

    它们的值是相同的,但是表达的意思不同:func是函数的首地址,它的类型是void(),&func表示一个指向函数func这个对象的地址,它的类型是void(*)(),因此它们所代表的地址是一样的,但类型不一样。

    按照&运算符本来的意义,它要求其操作数是一个对象,但函数名不是对象(函数才是对象),本来&func是非法的,但很久以前许多编译器就允许这么做。

    总结:

    在平时使用时,当需要传入一个函数指针做参数,直接传入函数名即可,不需要&func这样的写法。


二、pthread_create:

再来看pthread_create()这个函数的第三个参数就比较好理解了:

void *(*start_routine)(void *)

要传入的参数是一个函数指针:(*start_routine),
这个函数的返回值类型是 (void *),入参类型是 (void *)

所以,pthread_create的使用方法是这样的:

void *thread_callback(void *arg) {
    
    
	//do something
}

int main() {
    
    
	pthread_create(&tid, NULL, thread_callback, &arg);
}

三、回调函数:

1. 回调函数作用是什么?

回调函数最大的作用,就是 解耦

如果只是为了在一个函数中调用另一个函数,普通函数也是完全可以实现的(直接在函数参数中调用另一个函数名即可),库函数只需要提供一个接口给使用者调用:

void Library(void *(*Callback)(void *)) {
    
     }

这样一来,只要使用者改变传进库函数的参数不同,就可以实现不同的功能,非常的灵活,并且没有丝毫改变库函数的实现,这就是解耦。

回过头来想一想,pthread_create就是这样的一种使用回调函数的方式:

pthread线程库提供一个接口pthread_create供应用程序调用,应用程序将不同的线程回调函数(入口函数)传入进去,即可实现不同的线程功能:


void *pthread_A(void *arg) {
    
    

}

void *pthread_B(void *arg) {
    
    

}

int main() {
    
    
    pthread_create(&tid_a, NULL, pthread_A, NULL);
    pthread_create(&tid_b, NULL, pthread_B, NULL);
}

参考内容:

C语言回调函数详解

猜你喜欢

转载自blog.csdn.net/ArtAndLife/article/details/111060578