分析一套源代码的代码规范和风格并讨论如何改进优化代码

  我的工程实践选题是《智能仓库嵌入式操作系统》,我在github上找到的一个操作系统内核叫hurlex,地址:https://github.com/hurley25/hurlex-doc。作者在基于Intel x86架构的IBM PC机及其兼容计算机上构建出一个简单的操作系统内核。由于linux有可以自由使用的一系列的开源软件能很好的协助开发和调试工作,而在Windows下缺乏相应的免费工具,项目工作环境选择的是linux,故代码可能跟windows不兼容。同时,项目使用c语言编写,关于c语言的编程规范在本次博客中参考的是《华为C语言编程规范》。linux下c语言的编译器当然是使用gcc,ld作为连接器。管理整个项目作者使用的是GNU make。nasm作为汇编编译器,使用Intel风格的汇编语法。考虑到需要在一些C语言代码中内联汇编指令,作者gcc使用的是AT&T风格的汇编语法。为了工作的便利需要一个能调试其上运行着的操作系统的虚拟机,作者推荐的是qemu这款虚拟机。

源代码目录结构

  

  白色矩形框为文件夹,黄色为文件。作者把git文件、license、Makefile、readme文件都放在主目录hurlex下,每部分的代码都分成不同文件夹,对项目的操作以及项目的相关信息都可以在主目录下找到,这么做十分方便有关源程序的存储、查询、编译、链接等工作。对整个项目的管理都集中在Makefile里,如项目的编译、连接等。每个项目都要有readme文件,所有对项目的说明都集中在README里。作者还设置了工作目录scripts,所有的编译、链接等工作都在此目录中进行。但是作者没有设置工具目录,无法很好的存放文件编辑器等工具的信息。此外作者还设置了doc文件夹存放项目的相关文件如图片等,是一个好选择。

  作者的代码部分分成9个文件夹,arch文件夹存放的是涉及微处理部分的代码,其中包含了汇编语言,实现将内核代码跟底层代码的分离。其余的文件夹存放的是内核代码,include文件夹用于存放头文件,这样将头文件集中起来便于头文件的修改和引用,将.c文件和头文件分离,.c文件存放在其余文件夹中。作者这么做是符合c语言代码规范的,其中不足的一点是include文件中,头文件没有很好的分类只是设置了两个文件夹lib和mm,也就是说只将lib和mm中的头文件分类了,其他头文件混合在一起,不利于查找而且层次不够清晰。

文件名/类名/函数名/变量名等命名

  文件名作者使用了完整的单词或大家都可以理解的缩写单词来命名如:include,一个文件名包含两个及以上的单词使用下划线“_”来分隔如:block_dev,较长的单词作者使用头几个字母最为缩写如:doc、init,作者还采用了一些大家都公认的缩写如:mm、fs。作者的文件命名风格符合规范,足够清晰、明了,让读者能很快理解并且无歧义。

  类名和函数名作者采用的是多个单词描述,长单词使用头几个字母,多个单词间用下划线“_”分隔,类名后面跟上“_t”表示这是作者自己实现的类,如:block_dev_t、char_dev_t、atomic_t,函数名如:wakeup_task、schedule、clock_callback。类名和函数名作者做到了清晰明了,作为借口部分的类都能表明了所属模块。对于功能相反的函数能够使用正确的反义词给函数命名如:alloc_super_block/free_super_block。

  变量名有的使用多个单词描述,长单词使用头几个字母,多个单词间用下划线“_”分隔如:block_devs。有的使用单词首字母加另一个单词前几个字母组合的方式作为局部变量如:bdev,这种方式作为局部变量可以理解,作者为了防止歧义并没用采用作为全局变量。有的局部变量作者采用单字母的方式比如作为循环条件的 :while (p),p变量是单个字符,最为局部变量单个字符是可以用的,但是有时还是会产生歧义,所以作者这里最好还是不用比较好。

代码维护

  作者使用github进行维护,每次提交代码都有详细的修改记录

接口定义规范

  作者对每个接口都有说明,作者将接口函数的合法性检查交给接口函数本身负责。对于结构体接口,作者一般设置结构体名称、结构体可用标志、结构体操作、结构体大小。将属于同一个模块的结构体接口和函数接口放在一个同文件中,如block_dev.h中有:struct block_dev、struct io_request、void block_dev_init(void)、int add_block_dev(block_dev_t *bdev)等同属一个模块的函数和结构体。作者将每个函数设计成只完成一个功能,并且每个函数都用不多于300行的代码完成,这么做提高了函数的复用能力,并且便于排查问题,同时不使用过多的全局变量只有少数必要的全局变量和静态变量。对于结构体的设计,作者维持结构体的元素数量在适中的范围,对于元素过多的结构体设置子结构体,每个结构体关系都不复杂,结构体间关系清晰,极大的解耦模块,有利于单元测试和优化,如:

注释

  作者每个头文件都有注释,包含文件名、描述、版本、创建时间、编译器、作者、版权、修改日志等。作者每个函数头部都有注释,主要描述了函数的功能,但是没有指出参数、返回值、调用关系等,这样不利于函数理解的清晰,所以作者对函数的注释不是很好有改进的空间。作者对全局变量没有详细的注释,这样很容易造成混乱,全局变量应该有较详细的注释,包括对其功能、取值范围、哪些函数或过程存取它以及存取时注意事项等。

总结同类编程语言或项目在代码规范和风格的一般要求

1、注释的原则是有助于对程序的阅读理解,在该加的地方都加了,注释不宜太多也不能太少,注释语言必须准确、易懂、简洁

2、全局变量要有较详细的注释,包括对其功能、取值范围、哪些函数或过程存取它以及存取时注意事项等的说明

3、在代码的功能、意图层次上进行注释,提供有用、额外的信息

4、标识符的命名要清晰、明了,有明确含义,同时使用完整的单词或大家基本可以理解的缩写,避免使人产生误解,较短的单词可通过去掉“元音”形成缩写;较长的单词可取单词的头几个字母形成缩写;一些单词有大家公认的缩写

5、在同一软件产品内,应规划好接口部分标识符(变量、结构、函数及常量)的命名,防止编译、链接时产生冲突

6、去掉没必要的公共变量

7、仔细定义并明确公共变量的含义、作用、取值范围及公共变量间的关系

8、不同结构间的关系不要过于复杂

9、检查函数所有非参数输入的有效性,如数据文件、公共变量等

10、函数名应准确描述函数的功能

11、防止把没有关联的语句放到一个函数中

12、减少函数本身或函数间的递归调用

13、尽量减少循环嵌套层次

14、如果一个数据结构,在创建和销毁它的单线执行环境之外可见,那么它必须要有一个引用计数器

15、打印内核消息时,注意内核信息的拼写,不要用不规范的单词比如“ dont”,而要用“do not”或者“don't”。保证这些信息简单、清晰、明了、无歧义

16、如果函数的名字是 一个动作或者强制性的命令,那么这个函数应该返回错误代码 整数。如果是一个判断,那么函数应该返回一个“成功”布尔值。

17、如果一个函数有3行以上,就不要把它变成内联函数。这个原则的一个例外是,如果你知道某个参数是一个编译时常量,而且因为这个常量你确定编译器在编译时 能优化掉你的函数的大部分代码,那仍然可以给它加上inline关键字  

  

posted @ 2019-10-13 00:54  蒋松冬  阅读(217)  评论(0编辑  收藏  举报