C语言经典案例 void (*signal(int sig, void (*func)(int)))(int) 解读,带你学习函数名的本质,函数指针与指针函数,以及回调

(30) 2024-07-04 10:01:01

目录

  • 案例解读
    • 1 函数指针与指针函数
      • 1.1 指针函数
      • 1.2 函数指针
    • 2 解析void (*signal (int sinno,void(*func)(int)))(int)
    • 3 函数指针与回调
      • 3.1 ((void (*)(void))0x00)() 通过地址调用函数
      • 3.2 例程2
      • 3.3 用来解释例3.1和例3.2的C语言代码
      • 3.4 多种玩法

案例解读

函数: void (*signal (int sinno,void(*func)(int)))(int)

上述函数该如何读呢? 那么先了解下面的一组概念

1 函数指针与指针函数

指针函数: 本质是一个函数,其返回值为指针。

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

如果想详细更进一步的了解,可以参考下述文章: 函数指针和指针函数用法和区别

1.1 指针函数

指针函数: 简单的来说,就是一个返回指针的函数,其本质是一个函数,而该函数的返回值是一个指针

以下示例:

  • int fun(int x,int y); 这种函数应该都很熟悉,其实就是一个函数,然后返回值是一个 int 类型,是一个数值
  • int *fun(int x,int y); 这个函数就是一个指针函数。其返回值是一个 int 类型的指针,是一个地址。

总结: 指针函数和普通函数对比不过就是其返回了一个指针(即地址值)而已

1.2 函数指针

函数指针: 其本质是一个指针变量,该指针指向这个函数。总结来说,函数指针就是指向函数的指针。

以下示例:

  • int fun(int x,int y); 普通函数
  • int *fun(int x,int y); 指针函数
  • int (*fun)(int x,int y); 函数指针

函数指针是需要把一个函数的地址赋值给它,有两种写法:

  1. fun = &Function;
  2. fun = Function;

取地址运算符&不是必需的,因为一个函数标识符就表示了它的地址,如果是函数调用,还必须包含一个圆括号括起来的参数表。
调用函数指针的方式也有两种:

  1. x = (*fun)();
  2. x = fun();

两种方式均可,看个人习惯,如果理解其定义,随便怎么用都行

2 解析void (*signal (int sinno,void(*func)(int)))(int)

void (*signal(int sig, void (*func)(int)))(int) void (*func)(int) = A func 是一个指向函数的指针--该函数以int作为入参,返回值为空 signal(int sig, void (*func)(int)) = B signal 是一个函数-- 该函数有两个参数(一个是int型变量 sig 一个是指向函数的指针A) void (*B)(int) B是一个函数,返回值是一个指向函数(入参为int 返回值为空)的指针 signal 是一个函数-- 该函数有两个参数(一个是int型变量 sig 一个是指向函数(该函数以int作为入参,返回值为空 )的指针) ,signal的返回值是一个指向函数(入参为int 返回值为空)的指针 

3 函数指针与回调

函数指针,一般用途作为“回调函数”使用。

比如写了一个方法(函数),你希望调用它执行完处理之后,自动调用另一个后续的函数来处理继续的业务。
这个时候就可以把 “一个函数的入口地址”当是一个指针。 你的处理方法中接受函数参数时把这个指针传进来。

// 指针函数 int *myPlus(int a, int b) { 
    printf("plus:%d + % d = %d\n" ,a ,b, a + b ); return 0; } int *myMinus(int a, int b) { 
    printf("minus: %d - % d = %d\n", a, b, a - b); return 0; } //参数funtz int funt2( int a, int b , void *funtz) { 
    //pf为函数指针, int(*pf)(int, int) = ( int (*)(int,int ) )funtz; pf(a, b); return 0; } //主函数入口 int main() { 
    funt2(10,20, myPlus); //myPlus 是一个函数指针,它现在是作为一个参数在传递 funt2(10,20, myMinus); return 0; } 
  • 函数: 本质是一段可执行代码段。
  • 函数名: 指向这段代码段的首地址。

函数在内存中是有地址的,函数名对应着函数的首地址,既然有地址,就可以定义指针储存地址或更改指针的指向,存储函数(首)地址的指针,称为函数指针

3.1 ((void (*)(void))0x00)() 通过地址调用函数

#include<stdio.h> void print() { 
    printf("调用了print函数\n"); return; } int main() { 
    ((void (*)(void))0x00)(); return 0; } 

结果:

调用了print函数 

3.2 例程2

#include<stdio.h> int main() { 
    int a=100; //a的地址是0x0061fefc printf("打印a:%d\n",*(int*)0x0061fefc); return 0; } 

结果:

打印a:100 

3.3 用来解释例3.1和例3.2的C语言代码

#include<stdio.h> void print() { 
    printf("调用了print函数\n"); return; } int main() { 
    int a=100; printf("第一次打印a:%d\n",a); printf("a的地址是:%p\n",&a); //a的地址是0x0061fefc printf("第二次打印a:%d\n",*(int*)0x0061fefc); printf("\n"); print(); printf("print的地址是:%p\n",print); //print()的地址是0x00 ((void(*)(void))0x00)(); return 0; } 

结果:

第一次打印a:100 a的地址是:0061fefc 第二次打印a:100 调用了print函数 print的地址是:00 调用了print函数 

3.4 多种玩法

#include<stdio.h> void print() { 
    printf("调用了print函数\n"); return; } int main() { 
    //void (*p)(void)函数类型的基本格式 //第一种玩法 ((void (*)(void))0x00)(); //第二种玩法 void (*p1)(void)=print; p1(); //第三种玩法(不推荐) void (*p2)(void)=&print; (*p2)(); //第四种玩法 typedef void (*PF)(void); PF pf=print; pf(); return 0; } 

结果:

调用了print函数 调用了print函数 调用了print函数 调用了print函数 
THE END

发表回复