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

1.2 基于Turbo C 2.0环境的评估

在Turbo C 2.0环境里,C程序加上美好的面向对象机制,需要付出多少代价呢?答案是一个类增加0.5KB(即400 Bytes)左右,即使你的程序含有10个类(这已经是大系统了),也不过增加5KB左右。以下就以Turbo C 2.0 IDE的评估来说明这是一项很划算的策略。

1.2.1 加入第1个类

在C程序里加入第1个类时,你的程序大小会增加约0.5KB。如果继续加入,每增加一个类,会增加约0.3KB ~0.5KB。一般而言,如果系统环境里搭配有RTOS(Real-Time Operating System),通常不会斤斤计较500B的空间,本书就是针对这类环境而写的。现在先测量一个没有类的程序,代码如下所示:

        /*  CX01-01.C  */
        #include "stdio.h"
        static void turnOn() {  printf("Light is ON\n");  }
        static void turnOff()
        {  printf("Light is OFF\n");  }
        /*----------------------------------*/
        int main()
        {
          turnOn();   turnOff();
          getchar();   return 0;
        }

这是一个传统的Turbo C程序,并没有搭配LW_OOPC机制,此程序生成一个CX01-AP1.EXE的可执行文件,其大小如图1-1所示。

图1-1

这个程序在Turbo C 2.0 IDE上编译及连接之后,可执行文件的大小为10.4KB,我们将以这个范例来作为评估的基准,来算出增加第1个类必须付出的代价。现在就来配上LW_OOPC并规划一个Light类,代码如下所示。

定义Light类

    /*   light.h   */
    #include "lw_oopc.h"
    CLASS(Light)
    {
      void (*turnOn)();
      void (*turnOff)();
    };

实现Light类

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

编写main()主函数

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

建立一个Turbo C的TC_EX01.Prj文件

              light.c
              tc_ex01.c

此程序生成一个TC_EX01.EXE可执行文件,其大小如图1-2所示。

图1-2

这个程序在Turbo C 2.0 IDE上编译及连接之后,可执行文件的大小为10.9KB。

与前面CX01-AP1.EXE相比,增加了0.5KB。这是加入第1个类(即Light类)所付出的代价。当你看到这个OOPC程序时,可能对CLASS、CTOR等宏很好奇。不过,在本章里,我们只把焦点放在OOPC机制对程序大小的影响上,后续各章会对这些宏逐一说明。

1.2.2 加入第2个类

为了测量第2个类对程序大小的影响,我们把上述范例加以扩充,增加了三个一般函数,先测量此程序的大小,然后将此函数纳入第2个类里,最后再测量程序的大小,进行比较。现在就来加入三个函数,代码如下所示。

定义及实现三个函数

        /* control.c  */
        #include "stdio.h"
        #include "light.h"
        static Light *pl;
        void init()
        {  pl = (Light*)LightNew();   }
        void turnOn()
        {  pl->turnOn();  }
        void turnOff()
        {  pl->turnOff();  }

编写main()主函数

    /* cx01-01.c  */
    #include "stdio.h"
    #include "lw_oopc.h"
    extern void init();
    extern void turnOn();
    extern void turnOff();
    void main()
    {
      init();
      turnOn();   turnOff();
      getchar();   return;
    }

建立一个Turbo C的TC_EX02.Prj文件

          light.c
          control.c
          tc_ex02.c

此程序生成一个TC_EX02.EXE可执行文件,其大小如图1-3所示。

图1-3

此程序大小为11.2KB,比上一个程序增加了0.3KB,这不是由增加类而引起的,而是由增加init()等三个函数所引起的。我们先以此程序大小为准,然后将这三个函数纳入类里,再测量其大小,就可以看出新增类得付出多少代价了。现在就将其纳入新类(称为CTRL)里,代码如下所示。

定义CTRL类

    /*  ctrl.h   */
    #include "lw_oopc.h"
    #include "light.h"
    CLASS(CTRL)
    {
      void (*init)(CTRL*);
      void (*turnOn)(CTRL*);
      void (*turnOff)(CTRL*);
      Light *pl;
    };

实现CTRL类

    /* ctrl.c   */
    #include "stdio.h"
    #include "ctrl.h"
    extern void* LightNew();
    static void init(CTRL *t)
    {  t->pl = (Light*)LightNew();   }
    static void turnOn(CTRL *t)
    {  t->pl->turnOn(t->pl);  }
    static void turnOff(CTRL *t)
    {  t->pl->turnOff(t->pl);  }
    CTOR(CTRL)
      FUNCTION_SETTING(init, init)
      FUNCTION_SETTING(turnOn, turnOn)
      FUNCTION_SETTING(turnOff, turnOff)
    END_CTOR

编写main()主函数

    /* tc_ex02.c   */
    #include "stdio.h"
    #include "lw_oopc.h"
    #include "ctrl.h"
    extern void* CTRLNew();
    void main()
    {
      CTRL* ctrl = (CTRL*)CTRLNew();
      ctrl->init(ctrl);
      ctrl->turnOn(ctrl);
      ctrl->turnOff(ctrl);
      getchar();   return;
    }

建立一个Turbo C的TC_EX03.Prj文件

          light.c
          ctrl.c
          tc_ex03.c

此程序生成一个TC_EX03.EXE可执行文件,其大小如图1-4所示。

图1-4

此程序大小为11.9KB,与前面TC_EX02.EXE相比,增加了0.7KB。这是加入第2个类(即CTRL类)的代价。

1.2.3 加入第3个类

为了测量第3个类对程序大小的影响,我们把上述范例加以扩充,加了两个函数,先测量此程序的大小;之后将此函数纳入第3个类里,再测量程序的大小,进行比较。现在就来加入两个函数,代码如下所示。

定义及实现两个函数

        /* sw.c   */
        #include "stdio.h"
        void swDown()
        {  printf("SW is Down\n");  }
        void swUp()
        {  printf("SW is Up\n");  }

撰写main()主函数

        /* tc_ex04.c   */
        #include "stdio.h"
        #include "lw_oopc.h"
        #include "ctrl.h"
        extern void swDown();
        extern void swUp();
        void main()
        {
          CTRL* ctrl = (CTRL*)CTRLNew();
          ctrl->init(ctrl);
          ctrl->turnOn(ctrl);   swDown();
          ctrl->turnOff(ctrl);   swUp();
          getchar();
          return;
        }

建立一个Turbo C的TC_EX04.Prj文件

              light.c
              ctrl.c
              sw.c
              tc_ex04.c

此程序产生一个TC_EX04.EXE执行文件,其大小如图1-5所示。

图1-5

此程序大小为12.0KB。这比上一个程序增加了0.1KB,这其实不是由增加类而引起的,而是由增加swDown()等函数所影响的。我们先以此程序大小为准,然后将这两个函数纳入类里,再测量其大小,就可以看出新增类得付出多少代价了。现在就将其纳入新类(称为DoorSwitch)里,代码如下所示。

定义DoorSwitch类

    /*   DoorSwitch.h   */
    #include "lw_oopc.h"
    CLASS(DoorSwitch)
    {
      void (*swDown)();
      void (*swUp)();
    };

实现DoorSwitch类

    /* DoorSwitch.c   */
    #include "stdio.h"
    #include "switch.h"
    static void swDown()
    {  printf("SW is Down\n");  }
    static void swUp()
    {  printf("SW is Up\n");  }
    CTOR(DoorSwitch)
      FUNCTION_SETTING(swDown, swDown)
      FUNCTION_SETTING(swUp, swUp)
    END_CTOR

撰写main()主函数

    /* tc_ex05.c   */
    #include "stdio.h"
    #include "lw_oopc.h"
    #include "ctrl.h"
    #include "switch.h"
    void main()
    {
      CTRL* ctrl = CTRLNew();
      DoorSwitch *psw = DoorSwitchNew();
      ctrl->init(ctrl);
          ctrl->turnOn(ctrl);
          psw->swDown();
          ctrl->turnOff(ctrl);
          78psw->swUp();
          getchar();   return;
        }

建立一个Turbo C的TC_EX05.Prj文件

        light.c
        ctrl.c
        switch.c
        tc_ex05.c

此程序产生一个TC_EX05.EXE执行文件,如图1-6所示。

此程序大小为12.4KB。与前面TC_EX04.EXE相比,增加了0.4KB。这是加入第3个类(即DoorSwitch类)的代价。

图1-6

1.2.4 加入第4个类

为了测量第4个类对程序大小的影响,我们把上述范例加以扩充,加了两个函数,先测量此程序的大小;之后将此函数纳入第4个类里,再测量程序的大小,进行比较。现在就来加入两个函数,代码如下所示。

撰写两个新函数及main()主函数

        /* tc_ex06.c   */
        #include "stdio.h"
        #include "lw_oopc.h"
        #include "ctrl.h"
        #include "switch.h"
        double length, width;
        void init()
        { length = 10.5;   width = 5.125;  }
        void print_perimeter()
        {  printf("P = %f\n", 2*(length + width));  }
    void main()
    {
      CTRL* ctrl = (CTRL*)CTRLNew();
      DoorSwitch *psw = (DoorSwitch*)DoorSwitchNew();
      ctrl->init(ctrl);
      ctrl->turnOn(ctrl);
      psw->swDown();
      ctrl->turnOff(ctrl);
      psw->swUp();
      init();     print_perimeter();
      getchar();  return;
    }

建立一个Turbo C的TC_EX06.Prj文件

          light.c
          ctrl.c
          switch.c
          tc_ex06.c

此程序产生一个TC_EX06.EXE执行文件,如图1-7所示。

图1-7

此程序大小为26.5KB。这比上一个程序增加了14.1KB,这不是由增加类而引起的,而是由增加print_perimeter()等函数所影响的。我们先以此程序大小为准,然后将这两个函数纳入类里,再测量其大小,就可以看出新增类得付出多少代价了。现在就将其纳入新类(称为Rectangle)里,代码如下所示。

撰写Rectangle新类及main()主函数

    /* tc_ex07.c   */
    #include "stdio.h"
    #include "lw_oopc.h"
    #include "ctrl.h"
    #include "switch.h"
    CLASS(Rectangle)
    {
      void (*init)(Rectangle*);
      void (*print_perimeter)(Rectangle*);
      double length, width;
    };
    static void init(Rectangle *t)
    {
      t->length = 10.5;  t->width = 5.125;
    }
    static void pr_perimeter(Rectangle *t)
    {
      printf("P = %f\n", 2*(t->length + t->width));
    }
    CTOR(Rectangle)
      FUNCTION_SETTING(init, init)
      FUNCTION_SETTING(print_perimeter, pr_perimeter)
    END_CTOR
    /* --------------------------------------------------------------------- */
    void main()
    {
      CTRL* ctrl = (CTRL*)CTRLNew();
      DoorSwitch *psw = (DoorSwitch*)DoorSwitchNew();
      Rectangle *rect  = (Rectangle*)RectangleNew();
      ctrl->init(ctrl);
      ctrl->turnOn(ctrl);
      psw->swDown();
      ctrl->turnOff(ctrl);
      psw->swUp();
      rect->init(rect);
      rect->print_perimeter(rect);
      getchar();  return;
    }

建立一个Turbo C的TC_EX07.Prj文件

          light.c
          ctrl.c
          switch.c
          tc_ex07.c

此程序产生一个TC_EX07.EXE执行文件,如图1-8所示。

图1-8

此程序大小为26.8KB。与前面TC_EX06.EXE相比,增加了0.3KB。这是加入第4个类(即Rectangle类)的代价。

1.2.5 评估统计图

以上总共加入了四个类,如果你继续加入更多类时,会发现每一个类大约都增加0.3KB~0.5KB左右。如图1-9所示。

综合上述的评估,兹说明如下:

● 由于LW_OOPC是由C语言的宏(Macro)所建立的,在编译之前就已经全部被转为一般非对象化的C程序了。所以,类能与类外的一般函数并存于你的程序里。这意味着,你可以视你的内存资源的宽裕情形而决定写入多少个类,并非要全部类化(即对象化)不可。因此,程序大小与执行速度并不是决定要不要采用LW_OOPC类机制的关键因素。反而,如何藉由LW_OOPC改善嵌入式程序架构,以提升系统的稳定性和可靠性才是采用LW_OOPC的最主要诱因。因为程序员能自由地决定程序的形式,一方面满足硬件资源的限制,另一方面又能追求最顶级的美好结构。因此,对一个C程序员及其撰写的嵌入式软件而言,LW_OOPC只是给他(或它)黄袍加身,并不会伤害到龙体本身。

● 从图1-9中可以看到,如果你的TurboC程序使用LW_OOPC提供的机制,而且写了n个类时,其程序大小的增加量大约为n * 0.5KB。如果写了10个精简型的类(即n的值为10),大约需付出5KB的代价。一般而言,C程序能写到10个类已经算是复杂的了,只付出不到5KB代价,却能让复杂的程序得到美好结构和高度稳定性,真是非常划算的策略。

图1-9