C 程序可移植性_legend

来源:互联网 发布:网络电视机介绍 编辑:程序博客网 时间:2024/05/18 10:40


      C程序可移植性

 1. #define ,typedef ,sizeof() 的使用

   (1) typedef

   0. typedef使用方法 :

   typedef oldtype newtype;

   1. typedef定义与平台无关的新类型(提高程序可移植性) :

   如:定义一个叫 REAL 的浮点类型,在目标平台一上,让它表示最高精度的类型为:

   typedef long double REAL;

   在不支持 long double 的平台二上,改为:

   typedef double REAL;

   在连 double 都不支持的平台三上,改为:

   typedef float REAL;

   也就是说,当跨平台时,只要改下 typedef 本身就行,不用对其他源码做任何修改。

   标准库就广泛使用了这个技巧,比如size_t。

  2. typedef 不同于#define , 不是简单的文本替换,
  而是定义了一个新类型。


  如:typedef char * pStr;

  char string[4] = "abc";

  const char *p1 = string;

  const pStr p2 = string;

  p1++;

  p2++;

    是p2++出错了。这个问题再一次提醒我们:
  typedef和#define不同,它不是简单的

  文本替换。

  3. typedef 定义 复杂的类型 :如函数指针。


  (2)预定义宏的使用 :

  写程序请一定要考虑到你今后可能换个编译器。所以请使用预定义宏!比如MS的编译器就事先定义了__MSC,而Borland的就预先定义了__BORLAND_C。Sunplus GCC编译器也肯定有这样的宏。举个例子:setvect函数在Borland的实现中就叫setvect,而MS C/C++中却是_dos_setvet。如果你仅仅是简单的用setvect,那你的程序就很可能失去了移植到MS C下的可能。不过如果你这么写:

   #if  defined(  __MSC  )

       _dos_setvect( 0x09,  pgos_timer_handler ) ;

   #else

   #if  defined( __BORLAND_C  )

       setvect( 0x09,  pgos_timer_handler ) ;

   #endif

   #error Error ! Need MSC or Borland C to compile this programe !

   #endif




 2. int 类型的位数 :

  不同机器字长的int 类型数据是不同的,16位机器int 类型是16位的,
  32位int字长是32位。

  所以最好使用sizeof(int)来表示int 类型的字长。


 3. 字符是有符号数还是无符号数?

 4. 分层设计,隔离平台相关的代码。

 最上层和最下层都不具有良好的可移植性。
 最上层是GUI,大多数GUI都不是跨平台的,如Win32 SDK和MFC。
 最下层是API.

 API(Application Program Interface),API对于程序员来说就是系统提供的接口,任何涉及系统调用都要通过API来完成。对于不同的操作系统都有不同的一套API,也就是说对于不同的操作系统系统调用的接口是完全不同的。所以在API层我们是不能移植的。我们经常会调用系统API,由于这些API在C语言中没有对其封装,所以我们只能用使用其原始的API,对于原始的API在各个操作系统中他们命名不同,就不能跨平台移植。

 如:限制系统调用于一个函数中,减少对操作系统 的依赖。
 解析:几乎所有的商业软件为了提高其执行速度,
 都会含有依赖于特定操作系统的代码。

 在C程序设计中,当必须 使用系统调用时,最好是将所有的系统调用
 限制于一个主函数中,若要将此程序移植到两一个操作系统中,
 只需要修改此函数,而其余函数可原封不动。

 如:当需要调用系统功能以清屏,删行,置光标位置时,可生成
 以下函数。

 void op_sys_call(op,x,y)
 {
char op;
int x,y;
  {
  switch(op){
  case 1: clear_screen();break;
  case 2: clear_col();break;
  case 3: goto_xy(x,y);break;

  }

  }

 }

 如:以下代码可以帮助我们实现各平台之间的可移植:

#ifndef _WINDOWS_

       CreateThread();      //windows下线程的创建

#else

       Pthread_create();    //Linux下线程的创建。

#endif
对于头文件,也使用同样的预编译宏来实现。如:

#ifndef _WINDOWS_

       #include <windows.h>

#else

       #include <thread.h>

#endif


   最底层采用Adapter模式,把不同操作系统的API封装成一套统一的接口。至于封装成类还是封装成函数,要看你采用的C还是C++写的程序了。这看起来很简单,其实不尽然(看完整篇文章后你会明白的),它将耗去你大量的时间去编写代码,去测试它们。采用现存的程序库,是明智的做法,有很多这样的库,比如,C库有glib(GNOME的基础类),C++库有ACE(ADAPTIVE Communication Environment)等等,在开发第一个平台时就采用这些库,可以大大减少移植的工作量。

   最上层采用MVC模型,分离界面表现与内部逻辑代码。把大部分代码放到内部逻辑里面,界面仅仅是显示和接收输入,即使要换一套GUI,工作量也不大。这同时也是提高可测试性的手段之一,当然还有其它一些附加好处。所以即使你采用QT或者GTK+等跨平台的GUI设计软件界面,分离界面表现与内部逻辑也是非常有用的。

   若做到了以上两点,程序的可移植性基本上有保障了,其它的只是技术细节问题。

 5.事先熟悉各目标平台,合理抽象底层功能.

 这一点是建立在分层设计之上的,大多数底层函数,像线程、同步机制和IPC机制等等,不同平台提供的函数,几乎是一一对应的,封装这些函数很简单,实现Adapter的工作几乎只是体力活。然而,对于一些比较特殊的应用,如图形组件本身,就拿GTK+ 来说吧,基于X Window的功能和基于Win32的功能,两者差巨大,除了窗口、事件等基本概念外,几乎没有什么相同的,如果不事先了解各个平台的特性,在设计时就精心考虑的话,抽象出来的抽口在另外一个平台几乎无法实现。

6.尽量使用标准C/C++函数。

大多数平台都会实现POSIX(Portable Operating System Interface)规定的函数,但这些函数较原生(Native) 函数来说,性能上的表现可能较次一些,用起来也不如原生函数方便。但是,最好不要贪图这种便宜而使用原生函数函数,否则搬起的石头最终会轧到自己的脚。比如,文件操作就用fopen之类的函数,而不要用CreateFile之类的函数等。


预定义宏,可以用来检测你的C语言编译器是不是一个标准C编译器:

#if  defined( __STDC__ )

// This is a standerd ANSI C compiler

#else

// This is not a standerd C compiler, perhaps K&R C ???

#endif



7.小心数据标准数据类型:

不少人已经吃过int类型由16位转变成32位带来的苦头,这已经是陈年往事了,这里且不谈。你可知道char在有的系统上是有符号的,在有的系统是无符号的吗?你可知道wchar_t在Win32下是16位的,在Linux 下是32位的吗?你可知道有符号的1bit的位域,取值是0和-1而不是0和1吗?这些貌合神离的东东,端的是神出鬼没,一不小心着了它的道。

8. 内存对齐与字节序:

要避免写出需要内存对齐的或者对字节序有特殊要求的程序。


0 0
原创粉丝点击