1.1 函数指针的实质
函数指针的实质还是指针,还是指针变量。在64位系统中,所有的指针都是8字节,32位系统中都是4字节。函数指针、数组指针、普通指针之间并没有本质区别,区别在于指针指向的东西的类型不同。
函数的实质是一段代码,这一段代码在内存中是连续分布的,一个函数的大括号括起来的所有语句将来编译出来生成的可执行程序在内存中是连续的,所以对于函数来说很关键的就是函数中的第一句代码的地址,这个地址就是所谓的函数地址,在语言中用函数名这个符号来表示。
例如,可以通过打印函数名:
输出:
结合函数的实质,函数指针其实就是一个普通变量,这个普通变量的类型是函数指针变量类型,它里面存储的值就是某个函数的地址,也就是它的函数名这个符号在编译器中对应的值。
1.2 函数指针的语法和分析方法
语言本身是强类型语言,每一个变量都有自己的变量类型,编译器可以帮我们做严格的类型检查。所有的指针变量类型其实本质都是一样的,但是为什么在语言中要去区分它们,写法不一样呢,比如类型指针就写作,数组指针就写作,函数指针就得写得更复杂,主要就是给编译器提供信息做类型检查,同时在指针解引用时匹配正确的解析方式。
函数指针的语法是:
例如有个函数是:
则对应的函数指针:
该指针的类型是:。
举个栗子:
运行结果:
函数名和数组名最大的区别就是:函数名做右值时加不加效果和意义都是一样的,但是数组名做右值时加不加意义就不一样。
一个复杂的函数指针的实例:中的函数:
对应的函数指针是:
1.3 总结
函数指针的分析方法也是源于优先级与逐层剥离。
2.1 用函数指针调用执行函数
最简单的函数指针来调用函数的示例,在上面一部分中已经写过了。本部分用函数指针指向不同的函数来实现同一个调用执行不同的结果。如果学过或者等面向对象的语言,就会知道面向对象三大特征中有一个多态,多态就是同一个执行实际结果不一样。
举个栗子,实现一个简单的运算器:
运行结果:
2.2 结构体内嵌函数指针实现分层
程序为什么要分层?因为复杂程序东西太多一个人搞不定,需要更多人协同工作,于是乎就要分工。要分工先分层,分层之后各个层次由不同的人完成,然后再彼此调用组合共同工作。
本部分要完成一个计算器,但是设计了2个层次:上层是,实现应用程序框架;下层是,实现计算器。实际工作时是直接完成工作的,但是中的关键部分是调用的中的函数来完成的。
:
2.3总结:
第二部分和第一部分部分实际完成的是同一个习题,但是采用了不同的程序架构。对于简单问题来说,上节的不分层反而容易理解,反而简单;本节的分层代码不好理解,看起来有点把简单问题复杂化的意思。原因在于这个问题本身确实是简单问题,而简单问题就应该用简单方法处理。明知错误还要这样做的目的是演示这种分层的写代码的思路和方法。
分层写代码的思路是:有多个层次结合来完成任务,每个层次专注各自不同的领域和任务,不同层次之间用头文件来交互。分层之后上层为下层提供服务,上层写的代码是为了在下层中被调用。
上层注重业务逻辑,与我们最终的目标相直接关联,而没有具体干活的函数。下层注重实际干活的函数,注重为上层填充变量,并且将变量传递给上层中的函数,其实就是调用上层提供的接口函数来完成任务。下层代码中其实核心是一个结构体变量,比如这里的,写下层代码的逻辑其实很简单:第一步先定义结构体变量;第二步填充结构体变量;第三步调用上层写好的接口函数,把结构体变量传给它既可,在内核中大量应用这种编程思想。
3.1 typedef关键字的用法
是语言中一个关键字,作用是用来定义,或者叫重命名类型。C语言中的类型一共有2种:一种是编译器定义的原生类型,基础数据类型,如、之类的;另二种是用户自定义类型,不是语言自带的,如数组类型、结构体类型、函数类型等。
有时候自定义类型太长了,用起来不方便,所以用给它重命名一个短点的名字。注意:是给类型重命名,也就是说加工出来的都是类型,而不是变量。
举个栗子,用重命名类型:
定义,或者叫重命名的是类型而不是变量,类型是一个数据模板,变量是一个实在的数据,类型是不占内存的,而变量是占内存的。在面向对象的语言中:类型就是类,变量就是对象。
3.2 typedef与#define宏的区别
3.3 typedef与const
来看下面两重写法:
如果想得到这种效果,只能:
3.4 使用typedef的重要意义
- 1.简化类型的描述。
- 2.创造平台无关类型。
很多编程体系下倾向于不使用、等语言内建类型,因为这些类型本身和平台是相关的,比如在16位机器上是16位的,在32位机器上就是32位的。为了解决这个问题,很多程序使用自定义的中间类型来做缓冲,比如内核中大量使用了这种方法:内核中先定义:然后在特定的编码需要下用来替代。的标准库中全部使用了自定义类型,比如。
为什么要用代替?
的真实类型与操作系统有关,在32位OS中被普遍定义为:
而在64位OS中被定义为:
以函数为例,其函数原型如下:
该函数的作用是将一段内存中数据复制到另一端段内存中去,其中n就是复制内存块的大小,该大小显然是一个大于等于0的数,而也可以表示负数,这个时候如果用来修饰n,则n可表示的有用的数据范围会比大上一倍,因为表示的那一半负数取值范围是用不上的。同理对于64位机器,其内存可寻址空间有大了很多,这个时候就可以用来扩大n的可表示数据范围。使用的函数很多,通过就可以不用一一修改函数原型里的参数类型而直接修改对应的类型就可以了,例如可以这样定义:
版权声明:
本文来源网络,所有图片文章版权属于原作者,如有侵权,联系删除。
本文网址:https://www.mushiming.com/mjsbk/685.html