最近向Linux内核提交了一些驱动。在提交的过程中,我发现自己的代码离linux内核的编码风格要求还差得很远。一开始只是简单浏览了内核文档中的CodingStyle一文。真正写代码的时候,很多细节我都不会去管。然而,在不遵守规则的程序员队伍中,我并不是唯一一个。如果你查看drivers/staging下的代码,你会发现很多驱动并没有严格遵守内核的编码风格,而在很多驱动的TODO文件中,“checkpatch.plfixes”将是他们的目标之一(checkpatch.pl是用来检查代码是否符合编码风格的脚本)。不可否认,编码风格是仁智之事。比如微软提倡的匈牙利语命名法,在Linus看来就是一种脑残的做法。也许你不认同Linus制定的编码风格,但是在提交内核驱动的时候,最好还是以大局为重。对于这样一个巨大的市场式开发,随意编写代码肯定会带来严重的可维护性灾难。(题图来自:mota.ru)一些辅助工具当代码量达到一定程度后,手动检查和修改编码风格非常繁琐。幸运的是,我们还有一些工具可以使用。scripts/checkpatch.pl这是一个检查代码是否符合内核编码标准的脚本。顾名思义,checkpatch是用来检查补丁的,默认调用确实是一样的。如果用于查看原始文件,则需要加上“-f”选项。我们来看一段无聊的代码(文件名为print_msg.c):voidprint_msg(inta){switch(a){case1:printf("a==1\n");休息;情况2:printf("a==2\n");休息;}}这段代码的编码风格有没有问题?使用checkpatch.pl检查:scripts/checkpatch.pl-fprint_msg.c检查的结果是:ERROR:switchandcaseshouldbeatthesameindent#3:FILE:switch.c:3:+switch(a){+case1:[...]+case2:total:1errors,0warnings,12linescheckedswitch.c有样式问题,请检查。如果这些错误中的任何一个是误报,请将它们报告给维护者,请参阅MAINTAINERS中的CHECKPATCH。在Linux内核的编码风格中,switch和case需要相同的缩进。本例代码很少,只有一处错误,手工修改非常方便。如果类似的拧紧错误很多怎么办?scripts/Lindentscripts目录下的工具Lindent可以用来自动纠正缩进问题。提醒一下,使用Lindent需要系统安装缩进工具。对于上面的例子,执行Lindent命令:scripts/Lindentprint_msg.c得到的新代码是:voidprint_msg(inta){switch(a){case1:printf("a==1\n");休息;情况2:printf("a==2\n");休息;}}sedsed是一个流编辑器,其强大的功能可以帮助我们处理很多重复性的工作。例如,Linux内核的编码风格要求行尾不能有空格(包括制表符),可以使用sed去除这些空格。我自己的坏习惯经常在代码行的末尾留下一些空格。比如当一行代码太长需要改的时候,我总是下意识地在换行的地方打一个空格。另外,我常用的编辑器之一Kate,经常会在空行前留下几个缩进的Tabs,方便对齐(如下图)。手动去除这些尾随空格是一项繁重的工作,但使用sed则小菜一碟。命令格式如下:sed's/[\t]*$//g'your_code.c一些需要注意的代码风格缩进1.除注释、文档和Kconfig外,使用制表符缩进,不要使用空格,并且tab的宽度为8个字符;2.在switch...case...语句中,switch和case的缩进相同(参考上文);花括号3.花括号的使用参考K&R风格。如果是函数,则在新行打开大括号:intfunction(intx){bodyoffunction}否则,大括号立即位于语句的末尾:if(xistrue){wedoy如果只有一行语句,则不需要使用花括号:if(condition)action();但是,对于条件语句,如果一个分支是一行语句,另一个分支是多行语句,则需要保持一致并使用花括号:if(condition){do_this();do_that();}else{otherwise();}空格4.关键字“if,switch,case,for,do,while”后需要加空格,如:if(something)5。关键字“sizeof,typeof,alignof,or__attribute__”后不要加空格,如:sizeof(structfile)6.括号内的表达式两边不要加空格。例如下面是一个反面例子:sizeof(structfile)7.二元和三元运算符大部分两边都需要空格,比如"=+-<>*/%|&^<=>===!=?:“;8、一元运算符后不能有空格,如“&*+-~!sizeoftypeofalignof__attribute__defined”;9、前缀自增自减运算符后和后缀自增自减运算符(“++”和“--”)前不需要空格;10、结构成员运算符两边不需要空格(“.”和“->”);11、行尾不需要空格;Note12.UseC89's"/*...*/"styleinstead不是C99的"//..."风格;13.多行注释可以参考下面的例子:/**Thisisthepreferredstyleformulti-line*comments在Linux内核源代码中。*请一致使用。**说明:左侧一列星号,*开头和结尾几乎是空白行。*/Kconfig14,“config”定义了以下用TabEnter的语句,help下面的语句缩进了两个额外的空格,例如:configAUDITbool"Auditingsupport"dependsonNEThelp输出)。在没有CONFIG_AUDITSYSCALL的情况下不进行系统调用审计。宏15、多行宏定义需要用“do..while”封装,如:#definemacrofun(a,b,c)\do{\if(a==5)\do_this(b,c);\}while(0)函数的返回值16.函数返回值的定义也必须遵循一定的规则如果函数名是动作或者命令式语句,应该以错误码的形式返回(通常0表示成功,-Exxx形式的负数表示错误),如:do_something()如果函数名是判断语句,返回值应该类似于布尔值(通常1表示成功,0表示错误),如:something_is_present()[参考文献](1)Documentation/CodingStyle(2)http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/来源:http://www.cnblogs.com/wwang/archive/2011/02/24/1960283.html
