Cstyle的C语言笔记 ---UEFI开发过程中须培养的N个习惯

    有一句话说的很经典,好的程序不是给机器来读的,能被机器读懂的程序充其量算是正确的程序,而能被人读懂的程序才算是好程序。那怎么样的程序才算是人能读懂的程序呢,小弟不才虽没写过几句代码,但是还是想说说个人的看法。
    个人认为写好程序大概分为几个步骤:
1.写正确的程序,如果一个程序逻辑不对不能实现该有的功能,那么哪怕你写的再漂亮,用了再多的高级的编程技巧和算法,那也绝得不算是一个好的程序,只能算是一个失败的程序。
 
2.写自己看得懂的程序。或许有人会说我写的程序很好,很巧妙,用到了某种语言当中的非常巧妙的技巧,执行效率很高,占用资源很少,但是代码只有他一个人能看懂。或许如果过了一段时间之后它自己 再看当初自己写的代码也看不懂了。这种程序我们认为它不算是好程序。
 
3.写别人看得懂的程序。如果你写的程序给你的队友来读,他不不懂的话,那么你写的程序就不能算是好程序,真正的好的程序是随便把程序给谁来读,他们都能很快的并且准确的读懂你想写什么,就像是读一本小说,别人能够陶醉其中,而不是各种抱怨,各种读不懂,各种挑刺。
 
      那么怎么才能写好的程序呢?小弟随没写很多的代码,但是还算是读过不少,下面来给自己做一个总结,就以UEFI的代码作为实例:
 
一.合理的安排架构你的源码,把相关性最强的部分组合在一起,尽量做到模块内的内聚性,减少模块间的耦合性。
把功能相关的内容放在一起,比如你有一个OEM相关的功能,需要在SEC,PEI,dxe三个阶段都需要做一些特别的事情,那么你就可以建立一个模块,可以命名为OEMModule,它包含以下几个文件:OemSec.asm,OemPei.c,OemDxe.c,
Oemmake.mak,OemXxx.xxx等,在每一个文件里面实现相应阶段但功能类似的功能。

二.合理的利用开发语言中的一些封装的工具。
UEFI主要是用C语言开发的,那么我们就可以使用C语言当中的一些好的功能,列举如下:
1.在头文件里面使用#ifndef #endif来保证头文件只会被编译一次,加快编译速度和减少模块间的干扰。
 
2.使用#define来定义一些常量,比如数组长度,TURE FAILSE
 
3.使用#typedef来给我们自定义的变量重新取别名。如:
    #typedef UINT64    EFI_PHYSICAL_ADDRESS;
    #define EFI_SUCCESS  RETURN_SUCCESS       
4.使用#define来定义宏,把一些常见的语句封装成代码块,虽然这样会增加总代码量,但是可以使代码读起来更简洁。如:
    #define EFI_SIZE_TO_PAGES(Size)  (((Size) >> EFI_PAGE_SHIFT) + (((Size) & EFI_PAGE_MASK) ? 1 : 0))
 
5.使用#if等宏编译指令来控制编译顺序,方便对项目进行配置。类似于支持的处理器架构,是否打开编译优化选项,是否打开调试模式等,让同一个方法能支持多种功能。如:
    #if   defined (MDE_CPU_IA32)  #if defined DEBUG
6.合理的使用ASSERT()printf()CR()等工具,当出现issue的时候可以通过相应的工具把异常抛出来,方便调试。
 
7.合理的利用C语言中的结构体,共同体,位域,指针等来构造复杂的数据结构,并用其来服务我们要实现的功能。
 
8.合理的数据封装与隐藏:类似该函数里面的IN关键词标示出了,该函数的参数是输入的,EFI_HANDLEs是一个自定义变量,它展示给调用者是一个简单的Void *类型,只在其核心部分使用其真正的类型,通过Void *这个万能的指指针,很好的实现了数据的封装和实现的隐藏:CoreValidateHandle ( IN    EFI_HANDLE   UserHandle )

三.选择并形成一套自己的编程习惯,如命名规则等
    选择自己的变量函数命名规则,并长期坚持形成习惯。如:UEFI当中常用的几种习惯:
1.全局变量:LIST_ENTRY      gHandleList
2.结构内部变量: LIST_ENTRY      mProtocolDatabase   
3.类似驼峰命名法和匈牙利命名法的合体的命名规则: EFI_LOCK        gProtocolDatabaseLock

四.要写好的注释,而不仅仅是写注释。
    写好注释,而不是写注释,写错误的注释往往比没写注释更可怕。
/**
  Locate a certain GUID protocol interface in a Handle's protocols.
  @param  UserHandle             The handle to obtain the protocol interface on
  @param  Protocol               The GUID of the protocol
  @return The requested protocol interface for the handle
**/
PROTOCOL_INTERFACE  *
CoreGetProtocolInterface (
  IN  EFI_HANDLE                UserHandle,
  IN  EFI_GUID                  *Protocol
  )
{
  EFI_STATUS          Status;
  PROTOCOL_ENTRY      *ProtEntry;
  PROTOCOL_INTERFACE  *Prot;
  IHANDLE             *Handle;
  LIST_ENTRY          *Link;

  Status = CoreValidateHandle (UserHandle);
  if (EFI_ERROR (Status)) {
    return NULL;
  }
 
  Handle = (IHANDLE *)UserHandle;
 
  //
  // Look at each protocol interface for a match
  //
  for (Link = Handle->Protocols.ForwardLink; Link != &Handle->Protocols; Link = Link->ForwardLink) {
    Prot = CR(Link, PROTOCOL_INTERFACE, Link, PROTOCOL_INTERFACE_SIGNATURE);
    ProtEntry = Prot->Protocol;
    if (CompareGuid (&ProtEntry->ProtocolID, Protocol)) {
      return Prot;
    }
  }
  return NULL;
}

五.先到这里,下次再总结。

转载请注明出处
[email protected]  //  http://blog.csdn.net/CStyle_0x007

 

你可能感兴趣的:(style)