C语言原本是面向过程的编程语言,而面向过程编程,比较繁琐,代码重用性较低。相对而言,面向对象编程,代码重用性高,同时便于理解,是一种更加先进的编程方法。可喜的是,C语言通过适当组织处理,也可以类似于C++一样面向对象编程。下面就来介绍这种组织处理的过程(受linux C源码的启发)。
1.事物归类
面向对象,就是将研究或操作的硬件或变量(所谓对象)根据其属性及操作,归类到一起。例如,对于串口,有如下属性及操作:
①名称:usart1;②波特率;③缓冲区字节;④奇偶校验;⑤初始化:操作1;⑥发送字节:操作2;⑦发送字符串:操作3,等等。于是可以将这些属性和操作都归类到一个C结构体下。这个结构体就类似于一个串口类,所有的串口都可以定义成这种类的数据类型。这就完成了对象抽象化表示的过程。C代码举例如下:
struct USART_Class { // 定义一个结构体类型,相当于一个类
char * module;
USART_TypeDef *usart_num;
int baud_rate; // 属性1:波特率
int buffer_size; // 属性2:缓冲区字节数
void (*config)(void); // 初始化操作
void (*send_byte)(USART_TypeDef *USARTx, uint8_t ch); // 发送字节操作
void (*send_string)(USART_TypeDef *USARTx, char *str); // 发送字符串操作
};
由于C结构体成员不能直接为函数,所以成员定义为指向函数的指针。上述代码中诸如(*config)即为函数指针。
2.定义对象
我们要研究或操作的,具有某一类特性的具体事物,即是对象,例如串口1,LED1、定时器1等。我们定义一个串口对象:
struct USART_Class usart1_obj = {
.module = "usart1",
.usart_num = USART1;
.baud_rate = 115200,
.buffer_size = 4,
.config = usart_config,
.send_byte = usart_send_byte,
.send_string = usart_send_string,
};
//对象usart1操作对应的函数
void usart_config(void);
void usart_send_byte(USART_TypeDef *USARTx, uint8_t ch);
void usart_send_string(USART_TypeDef *USARTx, char *str);
3.引用对象属性或操作
引用对象的属性和操作,与引用结构体成员别无二致。例如,
usart1_obj.config(); //完成串口1的初始化
usart1_obj.send_byte(usart1.usart_num,'a'); //发送一个字节字母a
通过以上三个步骤,就能实现C语言的面向对象编程。当然,中间还有一些细节过程,调试的时候也会出现各种bug。不过这都没关系,只要我们在实践中不断探究和总结,这些问题都会迎刃而解。