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

案例解读

函数: 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))0x00401340)() 通过地址调用函数

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

int main()
{
    ((void (*)(void))0x00401340)();
    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()的地址是0x00401340
    ((void(*)(void))0x00401340)();

    return 0;
}

结果:

第一次打印a:100
a的地址是:0061fefc
第二次打印a:100

调用了print函数
print的地址是:00401340
调用了print函数

3.4 多种玩法

#include<stdio.h>

void print()
{
    printf("调用了print函数\n");
    return;
}

int main()
{
    //void (*p)(void)函数类型的基本格式

    //第一种玩法
    ((void (*)(void))0x00401340)();

    //第二种玩法
    void (*p1)(void)=print;
    p1();

    //第三种玩法(不推荐)
    void (*p2)(void)=&print;
    (*p2)();

    //第四种玩法
    typedef void (*PF)(void);
    PF pf=print;
    pf();

    return 0;
}

结果:

调用了print函数
调用了print函数
调用了print函数
调用了print函数
  • 7
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CDamogu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值