面向对象的C语言示例:QUEUE

[复制链接]
1448|0
 楼主| Simon21ic 发表于 2015-9-26 16:20 | 显示全部楼层 |阅读模式
VSF构架中,各个模块都是使用类的方式来实现的,最近做了一个queue的类,就拿这个作为例子,演示一下C语言中,面向对象的实现。
队列的模型很简单,就是一个链表,只是我增加了每个节点的权重,用于排序。
这里就以TCPIP的使用环境作为例子:
1. 高层是多任务的,可能会在短时间内,把多个需要发送的IP报文推给底层驱动。但是,底层的硬件只能一个一个把数据写到wifi芯片,那么这里就会需要一个缓冲队列,并且,新来的发送报文,添加到队列的尾部
2. TCP的接收窗口管理,TCP协议在接收数据的时候,在定义的接收窗口范围内的报文,都可以接收,但是,接收到的报文可能是无序的。那么接收的报文也是放到一个缓冲队列,但是,这里多了一个排序,根据报文的sequence来决定报文的位置。
当然,其他地方都可以用到,比如定时器管理模块,所有的定时器也都是链表,这里也是使用这个队列来实现排序的,最近要触发的定时器排在最前面。

在面向对象的方式中,以前说过,是由类和接口实现的,在C语言中,类就是一个结构,接口就是一个函数(或者叫类函数)。
类函数的一个特诊,就是第一个参数是类的实例指针,就是很多面向对象语言中说的this指针。
C++在定义类函数的时候,不需要显式的定义this参数,但是编译器会自动加上。那么C语言的话,那就只能显式的定义这个参数了。

  1. // queue
  2. struct vsfq_node_t
  3. {
  4.         uint32_t addr;
  5.         struct vsfq_node_t *next;
  6. };
  7. struct vsfq_t
  8. {
  9.         struct vsfq_node_t *head;
  10.         struct vsfq_node_t *tail;
  11. };

  12. void vsfq_init(struct vsfq_t *q);
  13. void vsfq_append(struct vsfq_t *q, struct vsfq_node_t *n);
  14. void vsfq_remove(struct vsfq_t *q, struct vsfq_node_t *n);
  15. void vsfq_enqueue(struct vsfq_t *q, struct vsfq_node_t *n);
  16. struct vsfq_node_t* vsfq_dequeue(struct vsfq_t *q);


这个就是队列的定义,以及类函数接口。
append为了适应上述第一种情况,把新的node加入到尾部。
enqueue则是根据node里的地址,插入到适合位置。
remove是用队列里移出指定的node,而dequeue则是按照顺序,拿出头部的node

功能知道的话,代码其实也就是那几行而已。
比如,vsfq_init:
  1. void vsfq_init(struct vsfq_t *q)
  2. {
  3.         q->head = q->tail = NULL;
  4. }
当然,这里的问题是,没有对指针做有效性检测。我们先忽略这些问题。

这里定义好queue的类后,就可以在应用中,声明的类直接集成自这个queue类就行。

C语言中,继承的2中方法:
1. 使用没有命名的结构体
  1. struct vsf_buffer_queue_t
  2. {
  3.         uint32_t addr;
  4.         struct vsf_buffer_queue_t *next;
  5.         
  6.         uint8_t *buffer;
  7. };
以上这个结构体,前面的部分完全兼容vsfq_node_t,直接可以使用vsfq_xxx的类函数来操作。
访问addr和next的方式,就是vsfq_node_t完全一样:var_name.addr和var_name.next
当然,一般建议这么写:
  1. struct vsf_buffer_queue_t
  2. {
  3.         struct
  4.         {
  5.                 uint32_t addr;
  6.                 struct vsf_buffer_queue_t *next;
  7.         };
  8.         
  9.         uint8_t *buffer;
  10. };
这里的结构没有名字,所以访问的方式一样:var_name.addr和var_name.next
当然,这个需要知道父类的内部结构,才可能这么实现。
2. 使用命令的结构体
  1. struct vsf_buffer_queue_t
  2. {
  3.         struct vsfq_node_t qnode;
  4.         uint8_t *buffer;
  5. };
这种方式是不是简单一些,一般单一继承都可以用这种方法,直接可以吧vsf_buffer_queue_t结构的指针,转换成vsfq_node_t结构的指针。
编译结果上不损失任何效率,只是在使用的时候,需要经过强制类型转换。
访问方式上也需要通过一个结构内的变量来访问:var_name.qnode.addr和var_name.qnode.next,当然,这个也只是影响C代码,不影响编译后的效率。

另外,代码没经过验证,有问题请自行脑补。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:www.versaloon.com --- under construction

266

主题

2597

帖子

104

粉丝
快速回复 在线客服 返回列表 返回顶部