微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 硬件工程师文库 > 周立功教你学C语言编程:结构体,使程序设计更方便——内置函数指针和嵌套结构体

周立功教你学C语言编程:结构体,使程序设计更方便——内置函数指针和嵌套结构体

时间:08-06 来源:ZLG致远电子 点击:

在每次细微改进后,通过运行单元测试以确保改进没有造成任何破坏,然后才去做下一次改进。如此往复周而复始,每次改进后都要运行,通过这种方式保证在改进系统设计的同时系统能够正常工作。

重构是持续进行的,而不是在项目结束时、发布版本时、迭代结束时、甚至每天下班时才进行。重构是每隔一个小时或半个小时就要去做的事情,通过重构可以持续地保持尽可能干净、简单且有表现力的代码。

大量的实践证明,重复可能是软件中一切邪恶的根源,许多原则和实践规则都是为了控制与消除重复而创建的。消除重复最好的方法就是抽象,即将所有公共的函数指针移到一个单独的结构体中,创建一个通用的Validator类型校验器。也就是说,如果两种事物相似的话,必定存在某种抽象能够统一它们,因此消除重复的行为会迫使团队提炼出许多的抽象,进一步减少代码之间的耦合。

自从发明子程序以来,软件开发领域的所有创新都是在不断尝试从源代码中消灭重复,即DRY(Don't Repeat Yourself)原则——别重复自己,因为重复黏贴会带来很多的问题,所以无论在哪里发现重复的代码,都必须消除它们。

2.  类型与变量

实际上,不管是范围值校验器还是奇偶校验器,其本质上都是校验器,其相同的属性是校验参数和待校验的值,其相同的行为可以共用一个函数指针调用不同的校验器。根据依赖倒置原则,将它们相同的属性和行为抽象为一个结构体类型Validator。比如:

在这里,还是以范围值校验为例,在RangeValidatro结构体中嵌套一个Validator类型的结构体,即将Validator类型的变量isa作为RangeValidator结构体的成员。比如:

由于&rangeValidator与&rangeValidator.isa的值相等,因此以下关系恒成立。比如:

即可将validateRange()函数原型:

中的"void *pThis"转换为"Validator *pThis",validatrRange()函数原型进化为:

3.  初始化

当将Validator类型的isa作为RangeValidator结构体成员时,显然rangeValidator.isa是一个结构体变量名,可以象任何普通结构体变量一样使用。使用Validator类型表达式:

即可引用rangeValidator变量的结构体成员isa的成员validate,即将rangeValidator.isa作为另一个点操作符的左操作符。比如:

由于点操作符的结合性是从左向右的,因此可以省略括号。其等价于:

只要将rangeValidator.isa看作一个Validator类型的变量即可。 

  

使用名为newRangeValidator的宏将结构体初始化:

其中,validateRange为范围值校验器函数名,使用方法如下:

宏展开后如下:

其中,外面的{}为RangeValidator结构体赋值,内部的{}为RangeValidator结构体的成员变量isa赋值。即:

如果有以下定义:

即可用pValidator引用RangeValidator的min和max。

由于pValidator与&rangeValidator.isa不仅类型相同且值相等,则以下关系同样成立:

因此可以利用这一特性获取validateRange()函数的地址,即pValidator->validate指向validateRange()。其调用形式如下:

4.  接口与实现

以范围值校验器为例,validatorCheck()函数的调用形式如下:

当然,也可以采取以下调用形式:

其效果是一样的。

为了便于阅读,如程序清单 2.24所示详细地展示了通用校验器的接口。

程序清单 2.24通用校验器接口(validator.h)

以范围值校验器为例,调用validateRange()的validatorCheck()函数的实现如下:

由此可见,validatorCheck()函数的实现不依赖任何具体校验器,通用校验器接口的实现详见程序清单 2.25。

程序清单 2.25  通用校验器接口的实现(validator.c)

在这里,作者并没有提供完整的代码,请读者补充完善。


Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top