谈谈Linux内核驱动的coding style
2011-11-11 13:37
295 查看
来至:/article/5083037.html
最近在向Linux内核提交一些驱动程序,在提交的过程中,发现自己的代码离Linux内核的codingstyle要求还是差很多。当初自己对内核文档里的CodingStyle一文只是粗略的浏览,真正写代码的时候在很多细节上会照顾不周。不过,在不遵守规则的程序员队伍里,我并不是孤独的。如果去看drivers/staging下的代码,就会发现很多驱动程序都没有严格遵守内核的codingstyle,而且在很多驱动程序的TODO文件里,都会把"checkpatch.plfixes"作为自己的目标之一(checkpatch.pl是用来检查代码是否符合coding
style的脚本)。
不可否认,codingstyle是仁者见仁、智者见智的事情。比如Microsoft所推崇的匈牙利命名法,在Linus看来就是及其脑残(braindamaged)的做法。也许您并不赞成Linus制定的codingstyle,但在提交内核驱动这件事上,最好还是以大局为重。对于这么一个庞大的集市式的开发来说,随意书写代码必将带来严重的可维护性的灾难。
我们来看一段无聊的代码(文件名为print_msg.c):
viewsourceprint?
这段代码的codingstyle是否有问题呢?用checkpatch.pl来检查一下:
scripts/checkpatch.pl-fprint_msg.c
检查的结果是:
viewsourceprint?
在Linux内核的codingstyle里,switch和case要求有相同的缩进。本例的代码很少,错误也只有这一个,手动修改很方便。如果类似的缩紧错误很多怎么办?
对于上面这个例子,执行Lindent命令:
scripts/Lindentprint_msg.c
得到的新代码是:
viewsourceprint?
我自己的习惯很差,经常在代码的行尾留下一些空格。比如一行代码过长需要换行时,总是下意识的在换行的地方敲一个空格。另外,我常用的编辑器之一的Kate,为了对齐的需要,经常在空行的前面留上几个缩进的Tab(如下图)。
手动去除这些行尾的空格是一件头大的事情,但对于sed来说不过是举手之劳。命令格式如下:
sed's/[\t]*$//g'your_code.c
2、switch...case...语句中,switch和case具有相同的缩进(参考上文);
如果是函数,左花括号另起一行:
viewsourceprint?
否则,花括号紧接在语句的最后:
viewsourceprint?
如果只有一行语句,则不需要用花括号:
viewsourceprint?
但是,对于条件语句来说,如果一个分支是一行语句,另一个分支是多行,则需要保持一致,使用花括号:
viewsourceprint?
viewsourceprint?
5、在关键字“sizeof,typeof,alignof,or__attribute__”之后不要加空格,如:
viewsourceprint?
6、在括号里的表达式两边不要加空格,比如,下面是一个反面的例子:
viewsourceprint?
7、大多说的二元和三元运算符两边需要空格,如“=+-<>*/%|&^<=>===!=?:”;
8、一元运算符后面不要空格,如“&*+-~!sizeoftypeofalignof__attribute__defined”;
9、在前缀自增自减运算符之后和后缀自增自减运算符之前不需要空格(“++”和“--”);
10、结构成员运算符(“.”和“->”)的两边不需要空格;
11、行尾不需要空格;
13、对于多行注释,可以参考下例:
viewsourceprint?
viewsourceprint?
viewsourceprint?
如果函数的名称是一种动作或者命令式的语句,应该以错误代码的形式返回(通常是0表示成功,-Exxx这种形式的负数表示错误),如:
viewsourceprint?
如果函数的名称是判断语句,则返回值应该类似与布尔值(通常1表示成功,0表示错误),如:
viewsourceprint?
【参考资料】
(1)Documentation/CodingStyle
(2)http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/
最近在向Linux内核提交一些驱动程序,在提交的过程中,发现自己的代码离Linux内核的codingstyle要求还是差很多。当初自己对内核文档里的CodingStyle一文只是粗略的浏览,真正写代码的时候在很多细节上会照顾不周。不过,在不遵守规则的程序员队伍里,我并不是孤独的。如果去看drivers/staging下的代码,就会发现很多驱动程序都没有严格遵守内核的codingstyle,而且在很多驱动程序的TODO文件里,都会把"checkpatch.plfixes"作为自己的目标之一(checkpatch.pl是用来检查代码是否符合coding
style的脚本)。
不可否认,codingstyle是仁者见仁、智者见智的事情。比如Microsoft所推崇的匈牙利命名法,在Linus看来就是及其脑残(braindamaged)的做法。也许您并不赞成Linus制定的codingstyle,但在提交内核驱动这件事上,最好还是以大局为重。对于这么一个庞大的集市式的开发来说,随意书写代码必将带来严重的可维护性的灾难。
一些辅助工具
当代码量达到一定程度时,手动去检查和修改codingstyle是非常繁琐的工作,幸好,我们还有一些工具可以使用。scripts/checkpatch.pl
这是一个检查代码是否符合内核编码规范的的脚本。顾名思义,checkpatch是用来检查patch的,默认的调用也确实如此。如果用来检查原文件,需要加上“-f”的选项。我们来看一段无聊的代码(文件名为print_msg.c):
01 | void print_msg( int a) |
02 | { |
03 | switch (a){ |
04 | case 1: |
05 | printf ( "a==1\n" ); |
06 | break ; |
07 |
08 | case 2: |
09 | printf ( "a==2\n" ); |
10 | break ; |
11 | } |
12 | } |
scripts/checkpatch.pl-fprint_msg.c
检查的结果是:
ERROR:switchandcaseshouldbeatthesameindent |
#3:FILE:switch.c:3: |
+switch(a){ |
+case1: |
[...] |
+case2: |
total:1errors,0warnings,12lineschecked |
switch.chasstyleproblems,pleasereview.Ifanyoftheseerrors |
arefalsepositivesreportthemtothemaintainer,see |
CHECKPATCHinMAINTAINERS. |
scripts/Lindent
scripts目录下的工具Lindent可以用来自动修改缩进问题。提醒一下,使用Lindent要求系统安装indent这个工具。对于上面这个例子,执行Lindent命令:
scripts/Lindentprint_msg.c
得到的新代码是:
01 | void print_msg( int a) |
02 | { |
03 | switch (a){ |
04 | case 1: |
05 | printf ( "a==1\n" ); |
06 | break ; |
07 |
08 | case 2: |
09 | printf ( "a==2\n" ); |
10 | break ; |
11 | } |
12 | } |
sed
sed是一个流编辑器,其强大的功能可以帮助我们处理很多重复性的工作。比如,Linux内核的codingstyle要求,行尾不能有空格(包括Tab),去除这些空格就可以借助sed。我自己的习惯很差,经常在代码的行尾留下一些空格。比如一行代码过长需要换行时,总是下意识的在换行的地方敲一个空格。另外,我常用的编辑器之一的Kate,为了对齐的需要,经常在空行的前面留上几个缩进的Tab(如下图)。
手动去除这些行尾的空格是一件头大的事情,但对于sed来说不过是举手之劳。命令格式如下:
sed's/[\t]*$//g'your_code.c
一些需要注意的CodingStyle
缩进
1、除了注释、文档和Kconfig之外,使用Tab缩进,而不是空格,并且Tab的宽度为8个字符;2、switch...case...语句中,switch和case具有相同的缩进(参考上文);
花括号
3、花括号的使用参考K&R风格。如果是函数,左花括号另起一行:
1 | int function( int
|
2 | { |
3 | bodyoffunction |
4 | } |
1 | if
true ){ |
2 | we do y |
3 | } |
1 | if
|
2 | action(); |
1 | if
|
2 | do_this(); |
3 | do_that(); |
4 | } else { |
5 | otherwise(); |
6 | } |
空格
4、在关键字“if,switch,case,for,do,while”之后需要加上空格,如:1 | if (something) |
1 | sizeof ( struct file) |
1 | sizeof ( struct file) |
8、一元运算符后面不要空格,如“&*+-~!sizeoftypeofalignof__attribute__defined”;
9、在前缀自增自减运算符之后和后缀自增自减运算符之前不需要空格(“++”和“--”);
10、结构成员运算符(“.”和“->”)的两边不需要空格;
11、行尾不需要空格;
注释
12、使用C89的“/*...*/”风格而不是C99的“//...”风格;13、对于多行注释,可以参考下例:
1 | /* |
2 | *Thisisthepreferredstyleformulti-line |
3 | *commentsintheLinuxkernelsourcecode. |
4 | *Pleaseuseitconsistently. |
5 | * |
6 | *Description:Acolumnofasterisksontheleftside, |
7 | *withbeginningandendingalmost-blanklines. |
8 | */ |
Kconfig
14、“config”定义下面的语句用Tab缩进,help下面的语句再额外缩进两个空格,如:1 | configAUDIT |
2 | bool"Auditingsupport" |
3 | dependsonNET |
4 | help |
5 | Enableauditinginfrastructurethatcanbeusedwithanother |
6 | kernelsubsystem,suchasSELinux(whichrequiresthisfor |
7 | loggingofavcmessagesoutput).Doesnotdosystem-call |
8 | auditingwithoutCONFIG_AUDITSYSCALL. |
宏
15、多行的宏定义需要用“do..while”封装,如:1 | #definemacrofun(a,b,c)\ |
2 | do
|
3 | if (a==5)\ |
4 | do_this(b,c);\ |
5 | } while (0) |
函数返回值
16、函数返回值的定义最好也要遵循一定的章法。如果函数的名称是一种动作或者命令式的语句,应该以错误代码的形式返回(通常是0表示成功,-Exxx这种形式的负数表示错误),如:
1 | do_something() |
1 | something_is_present() |
(1)
(2)
相关文章推荐
- 【转载】谈谈Linux内核驱动的coding style
- 谈谈Linux内核驱动的coding style
- 谈谈Linux内核驱动的coding style
- 谈谈Linux内核驱动的coding style
- 谈谈Linux内核驱动的coding style
- 谈谈Linux内核驱动的coding style
- 谈谈 Linux 内核驱动的编码风格
- Linux 内核代码风格--Kernel Coding Style(持续更新-20170616)
- 谈谈为 Linux 内核写驱动的编码规范
- 谈谈Linux内核驱动的coding style
- Linux 内核Coding Style整理
- 谈谈为 Linux 内核写驱动的编码规范
- 谈谈为 Linux 内核写驱动的编码规范
- 谈谈linux2.6内核的驱动框架 zz
- 谈谈linux2.6内核的驱动框架
- 谈谈linux2.6内核的驱动框架
- 编码风格——linux内核开发的coding style
- 谈谈linux2.6内核的驱动框架
- Linux kernel coding style 内核代码风格
- Linux2.6内核驱动与2.4的区别