• 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;
    }

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

    转载请注明出处
    Cstyle.z.zhou@gmail.com  //  http://blog.csdn.net/CStyle_0x007
  • 相关阅读:
    父亲对子女的话
    开通博客
    在linux下安装MySQLdb及基本操作
    java 词汇表速查手册
    java数据源的几种配置
    DBCP的参数配置
    Linux crontab定时执行任务
    很好看的Button CSS.
    C# 创建活动目录.txt
    解密存储过程
  • 原文地址:https://www.cnblogs.com/bbsno1/p/3279853.html
Copyright © 2020-2023  润新知