有一句话说的很经典,好的程序不是给机器来读的,能被机器读懂的程序充其量算是正确的程序,而能被人读懂的程序才算是好程序。那怎么样的程序才算是人能读懂的程序呢,小弟不才虽没写过几句代码,但是还是想说说个人的看法。
个人认为写好程序大概分为几个步骤:
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