LinuxSir.Org  
| 网站首页 | 注册账号 | 论坛帮助 |

欢迎来到LinuxSir.Org!
您还未登录,请登录后查看论坛,或者点击论坛上方的注册链接注册新账号。


发表新主题 回复
精华主题  
主题工具
旧 03-06-17, 12:32 第 1 帖
Sworder
 
 
 
注册会员  
  注册日期: Sep 2002
  帖子: 935
  精华: 4
 

标题: Linux内核编程风格-转自LinuxForum


原文见 /usr/src/linux/Documentation/CodingStyle。



Linux内核编程风格


这篇短小的文档用于描述linux内核编程中推荐的编程风格。编程风格是很个人
化的东西,我不想把我的观点_强加_给任何人,但这是我必须维护的代码中所遵守
的,我也建议其他部分的代码也能遵守它。请至少给这里的观点一些考虑。

首先,我建议你打印一份GNU代码风格,不是去读它,而是把它烧了,这是个很
不错的姿态。

不废话了,下面就是Linux内核编程风格:



第一章:缩进


制表符(tabs)占8个字符,所以缩进也是8个字符。有些异端运动想使用4个字符
(甚至是2个字符)的缩进,这和把PI(圆周率)定为3没什么两样。

原因:缩进的根本目的是用来清晰地标识一个控制块的起始。特别是当你连续盯
着屏幕看了20 个小时后,你就会体会到更长的缩进的好处了。

现在,有些人提出8字符缩进会使得代码太偏向右边,当使用80字符的终端
时很难阅读。答案是如果你需要三层以上的缩进,那么你已经完蛋了,应该改改
你的程序了。

简而言之,8字符缩进使得阅读代码更为容易,并且在你的缩进层次过深时提出
警告。应该留心这样的警告。
关于这一点,我不能苟同,4个字符的缩进确实有它的好处,缩进太多反而看着累。
而且有时候仅仅两层嵌套就会使代码很长。




第二章:括号的位置


括号位置的问题在C编程风格中经常被提出。和缩进大小不同,括号位置的选择
并没有太多技术上的原因,而更多的是个人的喜好。比如Kernighan和Ritchie的
弟子们把左括号放在一行的最后,把右括号放在一行的开始,象这样:

if (x is true) {
we do y
}


但是,函数是一种特殊的情况,函数的左括号放在下一行的开始,象这样:

int function(int x)
{
body of function
}


全世界的异端人士指出这种不一致的做法 ...嗯... 不太一致,但是所有思维正
确的人知道 (a) K&R是_对_的 (b) K&R是对的。而且,函数确实是特殊的(你在C
中无法对函数进行嵌套)。

注意到右括号完全占有单独的一行,_除非_当它后面还有未完成的语句,比如do
语句中的“while”或者if语句中的“else”,想这样:

do {
body of do-loop
} while (condition);




if (x == y) {
..
} else if (x > y) {
...
} else {
....
}


原因:K&R。

还有,注意到这种括号的布局方法还减少了空行(或者说是几乎是空行)的数目,
而且没有减小可读性。因为你屏幕上的空行是不可回收资源(这里想一下25行的
终端屏幕),这样你会有更多的空行用于加注释。



第三章:命名


C是个斯巴达式(崇尚简洁风格的)语言,所以你的命名方法也应该如此。与
Modula-2和Pascal程序员不同,C程序员不使用
ThisVariableIsATemporaryCounter这样可爱的名字。一个C程序员会把一个变量
叫做“tmp”,这样的变量名更容易写,而且理解起来也不算太难。

_但是_,尽管人人都会对大小写混杂的名字皱眉头,全局变量名则必须如此。管
一个全局函数叫“foo”是故意找岔。

_全局_变量(只有在_真正_需要时才使用)需要有个描述性强的名字,这点和全
局函数一样。如果你有个函数用于对活跃用户进行计数,你应该叫它
“count_active_users()”,而不是“cntusr()”。

把函数的类型加入到名字中(所谓的匈牙利命名法)是脑损伤的表现 - 编译器
知道类型,能够对它进行检查,这种命名法只会把程序员自己搞晕。难怪微软做
了那么多充满bug的程序。 哈哈^_^,有道理,不要作茧自缚

_局部_变量应该短小扼要。如果你有个随机的整数循环变量,可能最好叫它“i”。
把它叫做“loop_counter”是效率低下的,在不会发生混淆的情况下。类型地,
“tmp”可以被用于任何类型的存储临时值的变量。

如果你担心混淆你的局部变量,那么你就会有另一个问题,所谓的函数膨胀荷尔
蒙失衡综合症,请看下一章。



第四章:函数


函数应该短小而甜美,而且只能做一件事。他们应该只用一两屏幕(我们都知道,
ISO/ANSI标准屏幕大小是80x24)就能装下,只做并且做好一件事。

函数的最大长度应该与函数的复杂性和缩进层次成反比。所以,如果你有个只有
一个很长(但很简单)的case语句的函数,对许多case做一些很少的操作,那么
这个函数长点也没有关系。

但是,如果你有一个复杂的函数,你担心一个中等智力的高一学生可能无法理解,
那么你应该更严格地遵守最大长度限制。使用有描述性名字的帮助函数(你可以
让编译器in-line这些帮助函数,如果你认为性能很重要的话,而且编译器恐怕
会比你做的要好)。

函数的另一个指标是局部变量的数目,局部变量的数目不应超过5-10个,否则一
定是哪里有问题了。再设计一下这个函数,把它分解得更小一些。人的大脑一般
可以同时跟踪7个不同的东西,超过了7个就会晕菜。虽然你很聪明,不过可能你
有时会想理解一下两星期前所写的代码。



第五章:注释


注释是好东西,不过存在过分注释的危险。_永远_不要在注释中解释你的代码是
如何工作的:更好的做法是写出工作方式显而易见的代码,解释糟糕的代码是浪
费时间。

一般来说,注释应该说明代码在做什么,而不是怎么做。并且,不要把注释加在
函数主体中:如果函数太复杂以至于必须对各个部分进行注释,那么你可能要再
去读读第四章。你可以加入一些短小的注释来提醒或警告一些聪明(或难看)的
做法,但不要太过度。更好的选择是,把注释放在函数头,说明函数在做什么,
可能还包括它为什么做。



第六章:你的代码乱七八糟


没什么,我们都遇到过。你可能从老Unix用户那里听说过“GNU emacs”会自动
对齐C源代码,但缺省的设置不是很好(事实上,缺省设置比胡乱敲打还糟糕 -
一群使用GNU emacs猴子永远不会做出漂亮的程序)。
靠!我就是用emacs的!不过现在自动对齐还算可以了。

所以,你或者彻底仍掉GNU emacs,或者采用更理智的设置。如果选择后者,你
可一把下面的代码加到你的.emacs文件中:

(defun linux-c-mode ()
"C mode with adjusted defaults for use with the Linux kernel."
(interactive)
(c-mode)
(c-set-style "K&R")
(setq c-basic-offset 8))


这会定义 M-x linux-c-mode 命令。当编写Linux模块时,如果你把字符串“-*-
linux-c -*-”放在文件的头两行中,这个模式就会被自动激活。还有,如果你
想在编辑/usr/src/linux目录下的源文件时linux-c-mode被自动激活,你在你的.
emacs文件中需要加入

(setq auto-mode-alist (cons '("/usr/src/linux.*/.*\\.[ch]$" . linux-c-mode)
auto-mode-alist))

但是即使你用不了emacs,并不是世界末日:你还可以使用“indent”。

又一次,GNU indent使用了和GNU emacs一样的脑死亡设置,所以你需要给它一
些命令行选项。但是,这不算太坏,因为即使是GNU indent的作者们也意识到了
K&R的权威性(GNU的人也不是魔鬼,他们只是在这件事上被误导了),所以你可
以使用选项“-kr -i8”(表示“K&R,8字符缩进”)运行indent。

“indent”有很多选项,特别是注释布局部分,你可能想看看它的man手册。但
是请记住:“indent”不能修改糟糕的程序。
个人觉得现在emacs对缩进对齐的处理已经不错了,问题在于你使用不同的Linux
发行版,就会面对不同的.emacs文件,有时候我不得不随身携带我的.emacs文件,
或者把它放在我的email的存储箱里面



第七章:配置文件


配置选项 (arch/xxx/config.in,以及所有Config.in文件)使用了有些不同的
缩进方式。

代码中使用的是3字符缩进,config-选项中应该使用2字符缩进标识依赖关系。
后者只应用于bool/tristat选项。对于其他选项,采用你认为最合适的缩进方式
就可以了。例如:

if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate 'Apply nitroglycerine inside the keyboard (DANGEROUS)' CONFIG_BOOM
if [ "$CONFIG_BOOM" != "n" ]; then
bool ' Output nice messages when you explode' CONFIG_CHEER
fi
fi


一般来说,所有不稳定的选项应该标为CONFIG_EXPERIMENTAL。所有可能损坏数
据的的选项应该标为(DANGEROUS),其他的试验选项应该标为(EXPERIMENTAL)。



第八章:数据结构


供多线程使用的数据结构应该采用引用计数(reference counts)。在内核中,
垃圾回收(garbage collection)是不存在的(内核之外的垃圾回收效率不高),
这意味着你_必须_使用引用计数。

引用计数的使用能避免锁的使用,使不同的用户能够并行使用数据结构 - 不需
要担心结构会因为睡眠而突然消失。

注意到加锁_不是_引用计数的替代物。加锁用于保证数据结构的完整性,而引用
计数是一个内存管理技术。通常你两个都需要,不应该有任何混淆不清的地方。

一些数据结构可能使用两层的引用计数,当对不同的“类”都有使用的时候。子
类的计数统计所有子类用户的数目,当子类的计数为零时只对总计数减一。

这种“多层引用计数”的例子可以在内存管理代码(“struct mm_struct”:
mm_users和mm_cout)和文件系统代码(“struct super_block”:s_count和
s_active)中找到。

记住:如果另一个线程能够看见你的数据结构,而你却没有对它使用引用计数,
那么几乎可以肯定会有bug存在。







__________________
我的Blog: http://cookiebear.info/
老婆的Blog: http://cookiebear.info/rabbit/
  Sworder 当前离线   回复时引用此帖
旧 03-06-17, 18:26 第 2 帖
fingster
 
 
 
注册会员  
  注册日期: Jan 2003
  帖子: 900
  精华: 0
 

呵呵,猴子这个名字挺有意思的。这是我们寝室的昵称呢。
  fingster 当前离线   回复时引用此帖
旧 03-06-18, 12:21 第 3 帖
kj501
 
kj501 的头像
 
 
★☆版★主☆★  
  注册日期: Sep 2002
  我的住址: 贵州贵阳
  帖子: 5,317
  精华: 36
 

linuxforum有不少好东东,值得好好挖掘一下。







__________________
希望大家提问前先 google 关键词
希望大家提问前先看论坛的精华和置项的贴子
希望大家提问前先搜索论坛的相关内容
希望大家提问时把标题写清楚
希望大家贴代码时能保持缩进
LFS ID:8158
  kj501 当前离线   回复时引用此帖
旧 03-06-18, 19:06 第 4 帖
自由狼-台风
 
自由狼-台风 的头像
 
 
注册会员  
  注册日期: Jun 2002
  我的住址: 广州 游走中
  帖子: 1,022
  精华: 12
 

......

我还是习惯于教材的
代码:
#include<stdio.h> main() { printf(...); }







__________________
写了一个小说。决定不要TJ,但进度很慢。
http://typhoon.rocklv.net/novels/TFW/Cross_The_Galaxy/index.html
  自由狼-台风 当前离线   回复时引用此帖
旧 03-06-18, 19:07 第 5 帖
自由狼-台风
 
自由狼-台风 的头像
 
 
注册会员  
  注册日期: Jun 2002
  我的住址: 广州 游走中
  帖子: 1,022
  精华: 12
 

即无论何时都把上下两个大括号摆在一列,查错很方便。
  自由狼-台风 当前离线   回复时引用此帖
旧 03-06-19, 07:15 第 6 帖
kj501
 
kj501 的头像
 
 
★☆版★主☆★  
  注册日期: Sep 2002
  我的住址: 贵州贵阳
  帖子: 5,317
  精华: 36
 

K&R风格的main()函数就是把大括号摆在一列啊。但是其它函数就不这么办了。
  kj501 当前离线   回复时引用此帖
旧 03-06-19, 18:22 第 7 帖
libinary
 
libinary 的头像
 
 
退役版主  
  注册日期: Feb 2003
  我的住址: 西安
  帖子: 1,502
  精华: 4
 

呵呵,我的风格和APUE的查不多。
  libinary 当前离线   回复时引用此帖
旧 04-07-03, 17:46 第 8 帖
jhuangjiahua
 
jhuangjiahua 的头像
 
 
★☆版★主☆★  
  注册日期: Apr 2004
  我的住址: 深空
  帖子: 9,502
  精华: 19
 

更喜欢BSD风格.







__________________
-
每日抽一刻钟解答 ML 中初学者的问题,
每周抽两小时整理新学知识,发表体验 Blog/Wiki/mail 分享出去,
每周至少抽四个小时来翻译自个儿喜欢的自由软件的文档,
每月至少抽八小时编程,推进自个儿的项目,
每年至少参加一次自由软件的活动,传播自由软件思想,发展一名自由人…………

只要我们每个人都坚持下去!
10年!就可以改变中国软件的整体风貌!
          ── woodpecker.org.cn

───────────────────
linux.hiweed.com  ubuntu.org.cn  sf.net/projects/pycds
  jhuangjiahua 当前离线   回复时引用此帖
旧 04-07-06, 10:33 第 9 帖
x11 帅哥
 
x11 的头像
 
 
注册会员  
  注册日期: Nov 2002
  我的住址: 上海
  帖子: 2,793
  精华: 2
 

那介绍一下bsd风格嘛







__________________
-..- .---- .----
  x11 当前离线   回复时引用此帖
旧 04-08-16, 09:49 第 10 帖
lucifer
 
 
 
注册会员  
  注册日期: Jan 2003
  我的住址: 北京
  帖子: 750
  精华: 0
 

引用:
最初由 x11 发表
那介绍一下bsd风格嘛
在fbsd下,man 9 style

btw,引用计数可以避免互斥锁主要还是归功于我们没有使用不满足交换律的结构,呵呵
  lucifer 当前离线   回复时引用此帖
旧 04-11-01, 11:22 第 11 帖
elssann
 
 
 
注册会员  
  注册日期: Oct 2004
  帖子: 120
  精华: 1
 

引用计数的使用能避免锁的使用,使不同的用户能够并行使用数据结构 - 不需
要担心结构会因为睡眠而突然消失

---------------------------------------------
根据我的实际开发经验,引用计数要和锁一起用,因为在引用计数进行增加和减少的时候,需要对引用计数本身进行加锁.
  elssann 当前离线   回复时引用此帖
发表新主题 回复


主题工具

发帖规则
您 [不可以] 发表新主题
您 [不可以] 回复主题
您 [不可以] 上传附件
您 [不可以] 编辑您的帖子

已 [启用] BB 代码
已 [启用] 表情符号
已 [启用] IMG 代码
已 [禁用] HTML 代码
[论坛跳转…]


所有时间均为[北京时间]。现在的时间是 13:06


Powered by vBulletin 版本 3.6.8
版权所有 ©2000 - 2010, Jelsoft Enterprises Ltd.
官方中文技术支持: vBulletin 中文
版权所有 ©2002 - 2009, LinuxSir.Org