指针进阶第二弹~

一、引言

每日学习~天天开心!

我们今天来研究两个有趣的代码:

(*(void(*)())0)();
void(* signal(int,void(*)(int)))(int);

这两句代码是《C缺陷与陷阱》一书中提到的,我们看到这两行代码是不是会觉得很复杂,觉得很不能理解,那么今天就让我们一起探讨一下吧~

二、(*(void(*)())0)();

我们一层一层的看:

首先,我们注意到了  void(*)() ,这个是一个参数为空,返回类型为void的函数指针类型

紧接着,我们看到了一个0,我们会非常不解,为什么会有一个0,这就和当时提出这一行代码的那位前辈有关了,他想用0作为一个地址进行操作。所以这里是使用了强制类型转换(void(*)())0,把0强制转换成一个函数地址(void(*)()),这样就可以进行使用操作了。

接下来的就很容易理解了,首先对这个地址进行了解引用操作*(void(*)())0,这样我们通过地址找到了对应的函数。

最后,调用这个函数,(*(void(*)())0)();这样就实现了把0作为一个地址调用一个函数。

看到了这里,第一句代码,有没有觉得自己已经理解了呢。让我们往下看。

三、void(* signal(int,void(*)(int)))(int);

看到这句代码,只感觉头更疼了。没关系,我们慢慢来看。

和上面一样,首先,我们看到了  signal(int,void(*)(int)),signal是一个函数名,它有两个参数,分别为int类型和void(*)(int)类型,其中void(*)(int)是一个参数为int类型,返回值是void类型的函数指针类型。

但是,我们看到这里的时候就会发现,剩下的好像更复杂了,很奇怪的样子。

我们这样想,对于一个函数(返回类型  函数名(参数)),我们除掉函数名和参数,剩下的是不是就是返回类型,所以我们把 signal(int,void(*)(int))去掉,那么就会剩下void(* )(int)部分,我们会发现,这是一个函数指针。

所以,到这里,我们就可以得出结论了,这一个语句是一个函数的声明,这个函数名字为signal,参数为int和void(*)(int),返回类型是void(* )(int)。

四、关于void(* signal(int,void(*)(int)))(int);的思考

我们通常的函数声明是返回类型  函数名(参数);

所以我们可不可以写成void(* )(int) signal(int,void(* )(int));呢?我们输入编译器会发现,会出现错误,这个在语法上是不允许的。但是我们又觉得原式太复杂了,不容易阅读。

我们在这里,我们就想到了typedef关键词,我们可以使用它来进行重命名。

我们正常来使用,就是typedef 类型 新名字;例如:typedef unsigned int unit;

但是我们在这里不能写成:

typedef void(*)(int) pfun_t;

我们会发现编译器报错,我们要给一个函数指针重命名,我们要写成如下格式:

typedef void(*pfun_t)(int);

我们要把重命名的名字和*连在一起,我们可以这样理解,void(*pfun_t)(int)相当于定义了一个名字为pfun_t的函数指针,这样是不是更好理解呢?

综上所述,我们可以把它简化为:

typedef void(*pfun_t)(int);
pfun_t signal (int,pfun_t);

我们这样看着是不是也舒服了很多呢?

五、总结

今天的这两句代码,是不是也让大家对于函数指针有了一个更深的理解呢?今天的内容就到此结束啦!希望大家天天开心!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

独爱满天星

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

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

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

打赏作者

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

抵扣说明:

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

余额充值