OO Programing in C (2)

[b]OO Programing in C is not only POSSIBLE, but also PRACTICAL.[/b]
--------------------------------------------------------------------------------

“class“是很多OO编程语言里的关键字,它来源于OO鼻祖Smalltalk。class(类),是对一群有相同特性的对象的抽象概括,对象称为类的实例。在class里面可以存放有状态(变量),行为(函数/方法)....有关OO概念、方法的文章太多了,不再啰嗦。在C里面,唯一可以实现自定义类型的是struct,struct是C的OO编程最重要的工具。


一个最常见的技巧,就是用struct来"仿真"class: 在struct里面放入变量,函数指针,嵌入其他struct等。

以下例子摘自我最近刚开发完成的一个USB Firmware项目:

[code]
struct usb_device;
struct usb_ctl;

struct usb_iobuf {
int len; /* data length in the buffer */
unsigned char buf[USBEPFIFO_SIZE]; /* data buffer itself */
};

struct usb_endpoint { int type; /* endpoint type: BULKIN, BULKOUT, CTL, ISO ... */
int qlen; /* queue length */

xQueueHandle lock; /* semaphore lock */
xQueueHandle q; /* data queue (pointer of bulk_buf) */

int idx; /* endpoint index */
int epx; /* endpoint mark bit */
int cfg; /* endpoint configure */
int bank; /* current operation bank (for ping-pong mode) */
int txCount; /* used for ping-pong mode */ /* endpoint data process function */ void (*ep_process) (struct usb_device *dev, struct usb_endpoint *ep, xISRStatus *pxMessage);
};

struct usb_descriptor {
int type; /* descriptor type: device, conf, string or endpoint */
int idx; /* descriptor index (for string descriptor) */
int size; /* descriptor size */
void * data; /* descriptor data */
struct list_head list; /* link list of descriptors */
};

struct usb_deviceOps {
int (*init)(struct usb_device *dev); /* called when framework init usb device, add device descriptors, init private data ... etc. */
int (*reset)(struct usb_device *dev); /* called when reseted by host */
int (*switch_in)(struct usb_device *dev); /* called when switch in */
int (*switch_out)(struct usb_device *dev); /* called when swithc out */ /* called when HOST request class interface data */
void (*class_interface_req)(struct usb_device *dev, xUSB_REQUEST *pxRequest); /* called when HOST complete the data sending stage */ int (*ctl_data_comp)(struct usb_device *dev, xCONTROL_MESSAGE *pxMessage);
};

struct usb_ctlOps {
void (*ctl_transmit_null)(struct usb_ctl *ctl);
void (*ctl_send_stall)(struct usb_ctl *ctl);
void (*ctl_reset_ep0)(struct usb_ctl *ctl);
void (*ctl_detach_usb)(struct usb_ctl *ctl);
void (*ctl_attach_usb)(struct usb_ctl *ctl);
void (*ctl_send_data)(struct usb_ctl *ctl, unsigned char *data,
int req_len,
int send_len,
int is_des);
};


struct usb_ctl {
int addr; /* address alloced by host */
int conf; /* configuration set by host */
eDRIVER_STATE state; /* current status */
xCONTROL_MESSAGE tx; /* control transmit message */
xCONTROL_MESSAGE rx; /* control receive message */
struct ubufm *bufmn; /* 'usb_iobuf' buffer manager, shared by all usb devices */
int prio; /* the main task priority */
xTaskHandle task_handle; /* the main task handler */
struct usb_ctlOps *ctlOps; /* control endpoint operations */
};

struct usb_device {
char name[16]; /* device name, e.g. "usbser" */
struct usb_deviceOps *ops; /* usb device callback functions */

struct usb_ctl *ctl; /* usb control enpoint, provided by framework */
struct list_head desc_list; /* usb descriptors */
struct usb_endpoint *ep[MAX_ENDPOINTS]; /* endpoints */
int active; /* whether the device is active */
xQueueHandle ready; /* notify this queue when usb device ready */
void *private; /* device private data */
struct list_head list; /* link list of usb device */
};
[/code]
在这个例子,我用struct分别描述了USB设备,USB控制通道,USB端点,USB描述符和USB缓冲区对象。USB设备对象包含了若干个USB端点,一个USB控制通道指针,一个USB描述符表的表头(指向若干个USB描述符),和一个USB缓冲区管理对象。而且,USB设备对象还包含了name属性,一个由USB Framework调用的回调函数集,还有一个用于连接其他USB设备的链表节点。

值得一提的是,USB设备对象中有一个void *private 成员,可以指向任何数据。实际上在我的程序里,我实现了usb-serial和usb-mass-storage两个USB设备,对于usb-serial对象,private我弃之不用,而在usb-mass-storage对象中,private指向一个Mass storage对象,usb-mass-storage正是通过这个Mass storage对象访问外部大容量存储的(在我的程序里,Mass storage对象和一个MMC Card对象绑定,外部存储是SD/MMC卡)。由于对于每一种设备的具体实现来说,它知道private指向的是何种类型的设备,因此不会引起混乱。而外部程序根据需要在初始化USB设备对象前赋予private有意义的值——运行时动态绑定。

这一系列struct基本上如实地反映了USB DEVICE硬件逻辑和规范要求: "一个USB设备包含若干个端点,其中有一个固定的控制端点(端点0)。在枚举阶段USB设备要根据HOST的请求应答相应的描述符..."

现在回到OO的话题,这个例子中体现了"组合类":USB设备对象包含了USB端点对象,USB描述符对象...。还有动态绑定 (private成员)。从严格的OO意义上来看,好像有点"怪",不过我认为这恰恰是C的特点——简洁,直接。不信你用C++表达试试?也许会更漂亮,很OO,但是不一定会如此清爽!

P.S. : 熟悉USB Firmware开发的人可能对struct usb_endpoint中的epx,cfg,bank和txCount四个成员有异议,因为这些成员是和特定的硬件相关,并不是所有的USB硬件都支持ping-pong mode,所以bank和txCount不一定用得上,epx, cfg也可能因硬件的不同而不同。没错!更理想的设计是把与硬件相关的部分分离出来,用void *private指向各自的与硬件相关的配置——就像struct usb_device所采用方法,所以更好的版本应该是:

[code]struct usb_endpoint {
int type; /* endpoint type: BULKIN, BULKOUT, CTL, ISO ... */
int qlen; /* queue length */
xQueueHandle lock; /* semaphore lock */
xQueueHandle q; /* data queue (pointer of bulk_buf) */
int idx; /* endpoint index */

/* endpoint data process function */
void (*ep_process)(struct usb_device *dev, struct usb_endpoint *ep, xISRStatus *pxMessage);
void *private; /* endpoint private data (hardware relevant) */
};[/code]

tips: 用C表达的一个关键处就是要很好地应用struct来描述模型。


--TO BE CONTINUTED--
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值