UML+OOPC嵌入式C语言开发精讲
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

第2章 C程序的基本组成

2.1 认识C语言与LW_OOPC语言

2.1.1 C语言的身世背景

20世纪70年代,D. Richie及K. Thompson任职于美国贝尔实验室(Bell Labs)。当时Thompson正在设计Unix操作系统,而Richie负责设计新语言来编写Unix程序。新语言继承了Thompson原来设计的B语言,因此,称之为C语言。后来,Unix平步青云,成为标准操作系统,C随即水涨船高,受人青睐。

Unix以前的操作系统,皆以“汇编语言”(Assembly Language)编写。C问世后,逐渐取代了汇编语言的角色。Unix、DOS、Windows、OS/2等操作系统皆以C写成。到了2008年的今天,许多软件系统,如Google推出的Android手机平台,其内核模块仍是C语言的杰作呢!

C语言能获得极大的成功,D. Richie认为有五项主要因素:

1. C语言既不够优雅,也不够正式;

2. C语言符合程序员的需要,并且到处可见支持C语言的程序开发环境;

3. 众多人持续加以修改,与大环境保持交互;

4. 一开始把焦点设定在操作系统的开发是相当正确的,所谓好的开始是成功的一半;

5. 运气好。

2.1.2 C影响C++、Java、C#等语言文化

Java是由SUN公司的James Gosling率领的小组开发出来的。本来该小组的任务是要开发可以控制小家电、交互电视等的编程语言,之后因缘际会,与当时逐渐流行的Internet技术结合,在1995年发布并取名为Java。

Gosling在学生时代就深受C语言的洗礼,他在C.M.U.攻读博士学位的时候,曾经开发了一个C语言版本的Emacs,因而在Unix领域享有盛名。

Java从原本定位为家电控制语言,到后来成为Internet上热门的编程语言,在其发展过程中,从C++那里借鉴了许多宝贵的经验。例如效仿C++的标准程序库,推出一套完善的Java标准程序库;另外加上网络应用,以及最棘手的安全机制。至今,Java仍是Internet应用上最流行的编程语言(见图2-1)。

图2-1

到了2000年以后,Microsoft又从C++派生出C#作为与Java分庭抗礼的编程语言。之后连VB.NET都沿袭了C++的编译引擎设计,从而大幅提升了VB.NET的执行效率,并提供完整的OOP功能。

2.1.3 用C语言编写面向对象(Object-Oriented)程序

何谓OOPC,OOPC是指OOP(Object-Oriented Programming)与C语言结合,藉由C语言的Macro指令定义出OOP概念的关键字(Key Word)。这样,C程序员就能运用这些关键字来表达OOP的概念,如类、对象、信息、继承、接口等。

虽然OOPC程序的语法不像C++那么简洁,但是OOPC也有其亮丽的特色,就是编译后的程序所占的内存空间(Size)比C++程序小,能够满足像Embedded System等的内存限制,程序员也能有效地调整程序的瓶颈,从而提升其执行效率。

C++的功能齐全,但是在一般的嵌入式系统(Embedded System)开发上,经常只用到其中的一小部分功能,而不需要用到全部的机制,例如多重继承(Multiple Inheritance)、运算符的重载(Overloading)等。此时,许多嵌入式系统的开发者就舍弃C++的庞大身躯而回归到精简的C环境里。只是开发者舍弃C++的同时也舍弃了珍贵的OOP能力,实在太可惜了。

OOPC就是要弥补这个缺憾的。它是以C的宏写成的Header文件,可以任由C程序员对它瘦身美容,删去不需要的部分,挑出自己所需要的OOP特性,以小而美的身材满足嵌入式系统开发的需要。

以LW_OOPC为例

LW_OOPC是一种既轻便又快速的面向对象的C语言。做嵌入式开发的程序员还是比较青睐C语言的,只是C语言没有对象、类等概念,程序很容易变成意大利面型的结构,维护上比较费力。在1986年C++上市时,开发者希望大家改用C++,但是C++的效率不如C,因而不受嵌入式系统开发的程序员的喜爱。于是,MISOO团队便设计了一个既轻便又高效的OOPC语言。轻便的意思是它只用了约20个C宏语句而已,简单易学。其宏如下:

        /*  lw_oopc.h */  /* 这就是MISOO团队所设计的C */
        #include "malloc.h"
        #ifndef LOOPC_H
        #define LOOPC_H
        #define CLASS(type)\
        typedef struct type type; \
        struct type

        #define CTOR(type) \
        void* type##New() \
        { \
          struct type *t; \
          t = (struct type *)malloc(sizeof(struct type));
        }
        #define CTOR2(type, type2) \
        void* type2##New() \
        { \
          struct type *t; \
          t = (struct type *)malloc(sizeof(struct type));
        }
        #define END_CTOR return (void*)t;
        #define FUNCTION_SETTING(f1, f2)  t->f1 = f2;
        #define IMPLEMENTS(type) struct type type
        #define INTERFACE(type) struct type
        #endif
        /*    end    */

高效的意思是它没提供类继承,内部没有虚函数表(Virtual Function Table),所以仍保持着原来C语言的高效率。除了没有继承机制之外,它提供了类、对象、信息传递、接口和接口多态等常用的机制。目前受到不少C程序员的喜爱。

2.1.4 面向对象概念让UML与C携手合作

简单示例:从UML到OOPC程序

UML来自OO(Object-Oriented)领域,通过OO概念,善加运用UML,能让C程序员更上一层楼。由于UML也能创建硬件系统的模型,愈来愈多的嵌入式系统公司藉由UML来表达软件与硬件的分析与设计。

由于一般C语言并没有使用OO概念,因此将UML设计图实现为C程序的过程让人感到不顺畅。所以,MISOO团队将OO概念添加到C语言,让人们既能以OO概念去分析和设计,也能以OO概念去编写C程序。这样一来,从分析、设计到程序编写的过程就非常直截了当了。如下述的步骤。

Step-1 分析出一个类叫Light,它提供两项服务,以UML表达(见图2-2)。

图2-2

Step-2 实现为LW_OOPC程序。

基于上述的lw_oopc.h就可以定义出类了,例如定义一个Light类,其light.h的内容为:

    /*   light.h   */
    #include "lw_oopc.h"

    CLASS(Light)
    {
      void (*turnOn)();
      void (*turnOff)();
    };

类里的函数定义格式为:

      返回值的类型 (*函数名称)();

类定义好了,就开始编写函数的实现内容,代码如下:

    /* light.c   */
    #include "stdio.h"
    #include "light.h"

    static void turnOn()
    { printf("Light is ON\n");  }
    static void turnOff()
    { printf("Light is OFF\n");  }

    CTOR(Light)
      FUNCTION_SETTING(turnOn, turnOn)
      FUNCTION_SETTING(turnOff, turnOff)
    END_CTOR

这个FUNCTION_SETTING(turnOn, turnOn)宏的用意是:让类定义(.h文件)函数名称能够与实现的函数名称不同。例如在light.c里可写为:

          static void TurnLightOn()
          { ….. }
          CTOR(Light)
          {
            FUNCTION_SETTING(turnOn, TurnLightOn);
            …..
          }

这是创造.c文件自由替换的空间,是实现接口的重要基础。最后看看如何编写主程序:

    /* tc_ex01.c   */
    #include "stdio.h"
    #include "lw_oopc.h"
    #include "light.h"
    extern void* LightNew();
    void main()
    {
      Light* light = (Light*)LightNew();
      light->turnOn();
      light->turnOff();
      getchar();
      return;
    }

LightNew()是由CTOR宏所生成的类构造器(Constructor)。由于它定义于别的文件,所以必须加上extern void* LightNew();指令。生成对象的基本格式为:

      类名称*  对象指针 = (类名称*)类名称New();
      示例:Light* light=(Light*)LightNew()

然后就能通过对象指针去调用成员函数了。

使用Turbo C 2.0开发环境

创建一个项目文件名叫PRJ_EX01.PRJ,并输入内容,如图2-3所示。

图2-3

按ALT+R执行,则输出如图2-4所示的执行结果。

图2-4