最近在向linux内核提交一些驱动程序,在提交的过程中,发现自己的代码离linux内核的coding style要求还是差很多。当初自己对内核文档里的codingstyle一文只是粗略的浏览,真正写代码的时候在很多细节上会照顾不周。不过, 在不遵守规则的程序员队伍里,我并不是孤独的。如果去看drivers/staging下的代码,就会发现很多驱动程序都没有严格遵守内核的coding style,而且在很多驱动程序的todo文件里,都会把"checkpatch.pl fixes"作为自己的目标之一(checkpatch.pl是用来检查代码是否符合coding style的脚本)。
不可否认,coding style是仁者见仁、智者见智的事情。比如microsoft所推崇的匈牙利命名法,在linus看来就是及其脑残(brain damaged)的做法。也许您并不赞成linus制定的coding style,但在提交内核驱动这件事上,最好还是以大局为重。对于这么一个庞大的集市式的开发来说,随意书写代码必将带来严重的可维护性的灾难。
(题图来自:mota.ru)
<a target="_blank"></a>
当代码量达到一定程度时,手动去检查和修改coding style是非常繁琐的工作,幸好,我们还有一些工具可以使用。
这是一个检查代码是否符合内核编码规范的的脚本。顾名思义,checkpatch是用来检查patch的,默认的调用也确实如此。如果用来检查原文件,需要加上“-f”的选项。
我们来看一段无聊的代码(文件名为print_msg.c):
<code>void print_msg(int a)</code>
<code>{</code>
<code>switch (a) {</code>
<code>case 1:</code>
<code>printf("a == 1\n");</code>
<code>break;</code>
<code></code>
<code>case 2:</code>
<code>printf("a == 2\n");</code>
<code>}</code>
这段代码的coding style是否有问题呢?用checkpatch.pl来检查一下:
<code>scripts/checkpatch.pl -f print_msg.c</code>
检查的结果是:
<code>error: switch and case should be at the same indent</code>
<code>#3: file: switch.c:3:</code>
<code>+ switch (a) {</code>
<code>+ case 1:</code>
<code>[...]</code>
<code>+ case 2:</code>
<code>total: 1 errors, 0 warnings, 12 lines checked</code>
<code>switch.c has style problems, please review. if any of these errors</code>
<code>are false positives report them to the maintainer, see</code>
<code>checkpatch in maintainers.</code>
在linux内核的coding style里,switch和case要求有相同的缩进。本例的代码很少,错误也只有这一个,手动修改很方便。如果类似的缩紧错误很多怎么办?
scripts目录下的工具lindent可以用来自动修改缩进问题。提醒一下,使用lindent要求系统安装indent这个工具。
对于上面这个例子,执行lindent命令:
<code>scripts/lindent print_msg.c</code>
得到的新代码是:
sed是一个流编辑器,其强大的功能可以帮助我们处理很多重复性的工作。比如,linux内核的coding style要求,行尾不能有空格(包括tab),去除这些空格就可以借助sed。
我自己的习惯很差,经常在代码的行尾留下一些空格。比如一行代码过长需要换行时,总是下意识的在换行的地方敲一个空格。另外,我常用的编辑器之一的kate,为了对齐的需要,经常在空行的前面留上几个缩进的tab(如下图)。
手动去除这些行尾的空格是一件头大的事情,但对于sed来说不过是举手之劳。命令格式如下:
<code>sed 's/[ \t]*$//g' your_code.c</code>
1、除了注释、文档和kconfig之外,使用tab缩进,而不是空格,并且tab的宽度为8个字符;
2、switch ... case ...语句中,switch和case具有相同的缩进(参考上文);
3、花括号的使用参考k&r风格。
如果是函数,左花括号另起一行:
<code>int function(int x)</code>
<code>body of function</code>
否则,花括号紧接在语句的最后:
<code>if (x is true) {</code>
<code>we do y</code>
如果只有一行语句,则不需要用花括号:
<code>if (condition)</code>
<code>action();</code>
但是,对于条件语句来说,如果一个分支是一行语句,另一个分支是多行,则需要保持一致,使用花括号:
<code>if (condition) {</code>
<code>do_this();</code>
<code>do_that();</code>
<code>} else {</code>
<code>otherwise();</code>
4、在关键字“if, switch, case, for, do, while”之后需要加上空格,如:
<code>if (something)</code>
5、在关键字“sizeof, typeof, alignof, or __attribute__”之后不要加空格,如:
<code>sizeof(struct file)</code>
6、在括号里的表达式两边不要加空格,比如,下面是一个反面的例子:
<code>sizeof( struct file )</code>
7、大多说的二元和三元运算符两边需要空格,如“= + - < > * / % | & ^ <= >= == != ? :”;
8、一元运算符后面不要空格,如“& * + - ~ ! sizeof typeof alignof __attribute__ defined”;
9、在前缀自增自减运算符之后和后缀自增自减运算符之前不需要空格(“++”和“--”);
10、结构成员运算符(“.”和“->”)的两边不需要空格;
11、行尾不需要空格;
12、使用c89的“/* ... */”风格而不是c99的“// ...”风格;
13、对于多行注释,可以参考下例:
<code>/*</code>
<code>* this is the preferred style for multi-line</code>
<code>* comments in the linux kernel source code.</code>
<code>* please use it consistently.</code>
<code>*</code>
<code>* description: a column of asterisks on the left side,</code>
<code>* with beginning and ending almost-blank lines.</code>
<code>*/</code>
14、“config”定义下面的语句用tab缩进,help下面的语句再额外缩进两个空格,如:
<code>config audit</code>
<code>bool "auditing support"</code>
<code>depends on net</code>
<code>help</code>
<code>enable auditing infrastructure that can be used with another</code>
<code>kernel subsystem, such as selinux (which requires this for</code>
<code>logging of avc messages output). does not do system-call</code>
<code>auditing without config_auditsyscall.</code>
15、多行的宏定义需要用“do .. while”封装,如:
<code>#define macrofun(a, b, c) \</code>
<code>do { \</code>
<code>if (a == 5) \</code>
<code>do_this(b, c); \</code>
<code>} while (0)</code>
16、函数返回值的定义最好也要遵循一定的章法。
如果函数的名称是一种动作或者命令式的语句,应该以错误代码的形式返回(通常是0表示成功,-exxx这种形式的负数表示错误),如:
<code>do_something()</code>
如果函数的名称是判断语句,则返回值应该类似与布尔值(通常1表示成功,0表示错误),如:
<code>something_is_present()</code>
<b>原文发布时间为:2015-07-30</b>
<b></b>
<b>本文来自云栖社区合作伙伴“linux中国</b>