`
rubynroll
  • 浏览: 204634 次
  • 性别: Icon_minigender_1
  • 来自: Wgt
社区版块
存档分类
最新评论

OO Programing in C (2)

阅读更多
OO Programing in C is not only POSSIBLE, but also PRACTICAL.
--------------------------------------------------------------------------------

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


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

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

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 */
};

在这个例子,我用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所采用方法,所以更好的版本应该是:

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) */
};


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


--TO BE CONTINUTED--
分享到:
评论
4 楼 rubynroll 2008-01-08  
C在语法上不支持OO没错,但是思想是自由的,用C同样可以表达OO的思想,这是我想表达的。
手段很多,例如我帖子中,用struct来描述对象,用函数指针来出来对象的行为,用void *来实现动态绑定(多态?).... 等等。但我这里想说的是,不要认为用struct“仿真”了C++的class就是OO,或者说C的OO就是用struct“仿真”C++的class,不是,这只是技术手段,仔细看就会发现,这里的struct表达方式和C++的class是很大的不同,你看那些函数指针,传入的并不总是所在结构的指针(C++一定是this),这就说明了C可以跳出C++的对象模型,它的“对象”的“方法”是可以糅合其他“对象”的,是完全自由的,因此最终看到的是一个混合的对象模型。

如果纯粹用“相似行为的函数”来操作“对象”固然可以,但在从方法角度看,这叫“归纳”,而不是OO。用OO的另一个好处是可以“动态绑定”,我想这大概是很多驱动程序所需要的了。

3 楼 xombat 2008-01-08  
rubynroll 写道
seen 写道
firmware。。。看的头大,不懂

不过device driver是个很好的OO的切入点
hd的驱动就是个典型
的确如此。我想为什么device driver中用C可以很好地体现OO的思想,估计是因为硬件设备作为一个“对象”,它的行为和特性特别适合用C来描述,例如,一个结构体可以和一堆寄存器直接对应起来。

恩,可能是因为你需要将每个设备看成一个有数据有方法的对象才这样实现的,确实,在某些情况下使用oo思想来组织c代码能够降低使用时的复杂度,但是在多数情况下,在每个文件中包含一些相似行为的函数这样来组织代码还是更简单些,毕竟c不支持oo
2 楼 rubynroll 2007-12-31  
seen 写道
firmware。。。看的头大,不懂

不过device driver是个很好的OO的切入点
hd的驱动就是个典型
的确如此。我想为什么device driver中用C可以很好地体现OO的思想,估计是因为硬件设备作为一个“对象”,它的行为和特性特别适合用C来描述,例如,一个结构体可以和一堆寄存器直接对应起来。
1 楼 seen 2007-12-24  
firmware。。。看的头大,不懂

不过device driver是个很好的OO的切入点
hd的驱动就是个典型

相关推荐

    tcp ip programing in c

    标题《TCP/IP Sockets in C》指明了这是一本关于在C语言环境下进行TCP/IP套接字编程的指南。描述中提及的《TCP-IP Sockets in C: Practical Guide for Programmers》则强调了该书是一本面向程序员的实用指导手册。...

    OO programing with PHP5

    2. **继承**:继承允许创建新的类(子类)基于已存在的类(父类)。子类可以继承父类的所有公共和受保护的属性和方法,同时也可以添加自己的特性,实现代码重用和扩展。 3. **多态**:多态是指不同的对象对同一消息...

    c++ programing and c

    programing and cc++ programing and cc++ programing and cc++ programing and cc++ programing and cc++ programing and cc++ programing and cc++ programing and cc++ programing and cc++ programing and c

    The C Programing language

    根据提供的文件信息,实际内容与要求的C编程语言知识点不符,该文件内容为一份小品剧本,因此将基于剧本中的元素进行无关内容的剔除,接下来将围绕标题“C编程语言”及其描述来构建相关知识点。 ### C编程语言 ###...

    Programming the Microchip PIC in C

    《Programming the Microchip PIC in C》这本书由Nigel Gardner撰写,是一本介绍如何使用C语言编程Microchip PIC微控制器的基础指南。本书旨在为读者提供从零开始学习如何使用C语言进行PIC微控制器编程的全面指导。 ...

    The c programing language

    2. **结构化编程**:C语言支持结构化编程,通过函数组织代码,使程序结构清晰,易于维护。 3. **丰富的库函数**:C标准库提供了大量功能强大的函数,如I/O操作、字符串处理、数学运算等。 4. **可移植性**:C语言...

    programing in GDI+

    GDI+ SDK参考,GDI+编程入门,GDI+编程例子

    programing in lua

    Lua由标准C编写而成,几乎在所有操作系统和平台上都可以编译,运行。Lua并没有提供强大的库,这是由它的定位决定的。所以Lua不适合作为开发独立应用程序的语言。Lua 有一个同时进行的JIT项目,提供在特定平台上的...

    The C programing language

    The C programing language 发明C的科学家写的书

    Programing-in-C

    本资料“Programming-in-C”旨在为大学班级提供一个全面的C语言学习资源,帮助初学者建立起扎实的编程基础。 1. **C语言简介** C语言是一种结构化编程语言,它的语法清晰,允许直接操作硬件,这使得它在系统编程和...

    C-programing.rar_C programing答案

    "C-programing.rar_C programing答案"这个压缩包文件显然包含了关于C语言编程作业的答案,这些答案可能是教师为了帮助学生理解和解决编程问题而提供的。虽然答案可能不是唯一的,因为C语言的灵活性允许多种方法实现...

    the c programing language.rar

    the c programing language,kr编写,适合入门者学习,适合大学生学习,适合自学,c圣经,非常通俗易懂,配合答案食用更佳

Global site tag (gtag.js) - Google Analytics