ivaneeo's blog

          自由的力量,自由的生活。

            BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
            669 Posts :: 0 Stories :: 64 Comments :: 0 Trackbacks

          這篇短小的文檔用于描述linux內(nèi)核編程中推薦的編程風格。編程風格是很個人
          化的東西,我不想把我的觀點_強加_給任何人,但這是我必須維護的代碼中所遵守
          的,我也建議其他部分的代碼也能遵守它。請至少給這里的觀點一些考慮。

          首先,我建議你打印一份GNU代碼風格,不是去讀它,而是把它燒了,這是個很
          不錯的姿態(tài)。

          不廢話了,下面就是Linux內(nèi)核編程風格:

                          第一章:縮進

          制表符(tabs)占8個字符,所以縮進也是8個字符。有些異端運動想使用4個字符
          (甚至是2個字符)的縮進,這和把PI(圓周率)定為3沒什么兩樣。

          原因:縮進的根本目的是用來清晰地標識一個控制塊的起始。特別是當你連續(xù)盯
          著屏幕看了20
          個小時后,你就會體會到更長的縮進的好處了。

          現(xiàn)在,有些人提出8字符縮進會使得代碼太偏向右邊,當使用80字符的終端
          時很難閱讀。答案是如果你需要三層以上的縮進,那么你已經(jīng)完蛋了,應該改改
          你的程序了。

          簡而言之,8字符縮進使得閱讀代碼更為容易,并且在你的縮進層次過深時提出
          警告。應該留心這樣的警告。

                          第二章:括號的位置

          括號位置的問題在C編程風格中經(jīng)常被提出。和縮進大小不同,括號位置的選擇
          并沒有太多技術(shù)上的原因,而更多的是個人的喜好。比如Kernighan和Ritchie的
          弟子們把左括號放在一行的最后,把右括號放在一行的開始,象這樣:

                  if (x is true) {

                          we do y

                  }

          但是,函數(shù)是一種特殊的情況,函數(shù)的左括號放在下一行的開始,象這樣:

                  int function(int x)

                  {

                          body of function

                  }

          全世界的異端人士指出這種不一致的做法 ...嗯...
          不太一致,但是所有思維正
          確的人知道 (a) K&R是_對_的 (b)
          K&R是對的。而且,函數(shù)確實是特殊的(你在C
          中無法對函數(shù)進行嵌套)。

          注意到右括號完全占有單獨的一行,_除非_當它后面還有未完成的語句,比如do
          語句中的“while”或者if語句中的“else”,想這樣:

                  do {

                          body of do-loop

                  } while (condition);


                  if (x == y) {

                          ..

                  } else if (x > y) {

                          ...

                  } else {

                          ....

                  }

          原因:K&R。

          還有,注意到這種括號的布局方法還減少了空行(或者說是幾乎是空行)的數(shù)目,
          而且沒有減小可讀性。因為你屏幕上的空行是不可回收資源(這里想一下25行的
          終端屏幕),這樣你會有更多的空行用于加注釋。

                          第三章:命名

          C是個斯巴達式(崇尚簡潔風格的)語言,所以你的命名方法也應該如此。與
          Modula-2和Pascal程序員不同,C程序員不使用
          ThisVariableIsATemporaryCounter這樣可愛的名字。一個C程序員會把一個變量
          叫做“tmp”,這樣的變量名更容易寫,而且理解起來也不算太難。

          _但是_,盡管人人都會對大小寫混雜的名字皺眉頭,全局變量名則必須如此。管
          一個全局函數(shù)叫“foo”是故意找岔。

          _全局_變量(只有在_真正_需要時才使用)需要有個描述性強的名字,這點和全
          局函數(shù)一樣。如果你有個函數(shù)用于對活躍用戶進行計數(shù),你嬰兒叫它
          “count_active_users()”,而不是“cntusr()”。

          把函數(shù)的類型加入到名字中(所謂的匈牙利命名法)是腦損傷的表現(xiàn)
          - 編譯器
          知道類型,能夠?qū)λM行檢查,這種命名法只會把程序員自己搞暈。難怪微軟做
          了那么多充滿bug的程序。

          _局部_變量應該短小扼要。如果你有個隨機的整數(shù)循環(huán)變量,可能最好叫它“i”。
          把它叫做“l(fā)oop_counter”是效率低下的,在不會發(fā)生混淆的情況下。類型地,
          “tmp”可以被用于任何類型的存儲臨時值的變量。

          如果你擔心混淆你的局部變量,那么你就會有另一個問題,所謂的函數(shù)膨脹荷爾
          蒙失衡綜合癥,請看下一章。

                          第四章:函數(shù)

          函數(shù)應該短小而甜美,而且只能做一件事。他們應該只用一兩屏幕(我們都知道,
          ISO/ANSI標準屏幕大小是80x24)就能裝下,只做并且做好一件事。

          函數(shù)的最大長度應該與函數(shù)的復雜性和縮進層次成反比。所以,如果你有個只有
          一個很長(但很簡單)的case語句的函數(shù),對許多case做一些很少的操作,那么
          這個函數(shù)長點也沒有關(guān)系。

          但是,如果你有一個復雜的函數(shù),你擔心一個中等智力的高一學生可能無法理解,
          那么你應該更嚴格地遵守最大長度限制。使用有描述性名字的幫助函數(shù)(你可以
          讓編譯器in-line這些幫助函數(shù),如果你認為性能很重要的話,而且編譯器恐怕
          會比你做的要好)。

          函數(shù)的另一個指標是局部變量的數(shù)目,局部變量的數(shù)目不應超過5-10個,否則一
          定是哪里有問題了。再設計一下這個函數(shù),把它分解得更小一些。人的大腦一般
          可以同時跟蹤7個不同的東西,超過了7個就會暈菜。雖然你很聰明,不過可能你
          有時會想理解一下兩星期前所寫的代碼。

                          第五章:注釋

          注釋是好東西,不過存在過分注釋的危險。_永遠_不要在注釋中解釋你的代碼是
          如何工作的:更好的做法是寫出工作方式顯而易見的代碼,解釋糟糕的代碼是浪
          費時間。

          一般來說,注釋應該說明代碼在做什么,而不是怎么做。并且,不要把注釋加在
          函數(shù)主體中:如果函數(shù)太復雜以至于必須對各個部分進行注釋,那么你可能要再
          去讀讀第四章。你可以加入一些短小的注釋來提醒或警告一些聰明(或難看)的
          做法,但不要太過度。更好的選擇是,把注釋放在函數(shù)頭,說明函數(shù)在做什么,
          可能還包括它為什么做。

                          第六章:你的代碼亂七八糟

          沒什么,我們都遇到過。你可能從老Unix用戶那里聽說過“GNU
          emacs”會自動
          對齊C源代碼,但缺省的設置不是很好(事實上,缺省設置比胡亂敲打還糟糕
          -
          一群使用GNU 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的權(quán)威性(GNU的人也不是魔鬼,他們只是在這件事上被誤導了),所以你可
          以使用選項“-kr
          -i8”(表示“K&R,8字符縮進”)運行indent。

          “indent”有很多選項,特別是注釋布局部分,你可能想看看它的man手冊。但
          是請記住:“indent”不能修改糟糕的程序。

                          第七章:配置文件

          配置選項
          (arch/xxx/config.in,以及所有Config.in文件)使用了有些不同的
          縮進方式。

          代碼中使用的是3字符縮進,config-選項中應該使用2字符縮進標識依賴關(guān)系。
          后者只應用于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

          一般來說,所有不穩(wěn)定的選項應該標為CONFIG_EXPERIMENTAL。所有可能損壞數(shù)
          據(jù)的的選項應該標為(DANGEROUS),其他的試驗選項應該標為(EXPERIMENTAL)。

                          第八章:數(shù)據(jù)結(jié)構(gòu)

          供多線程使用的數(shù)據(jù)結(jié)構(gòu)應該采用引用計數(shù)(reference
          counts)。在內(nèi)核中,
          垃圾回收(garbage
          collection)是不存在的(內(nèi)核之外的垃圾回收效率不高),
          這意味著你_必須_使用引用計數(shù)。

          引用計數(shù)的使用能避免鎖的使用,使不同的用戶能夠并行使用數(shù)據(jù)結(jié)構(gòu)
          - 不需
          要擔心結(jié)構(gòu)會因為睡眠而突然消失。

          注意到加鎖_不是_引用計數(shù)的替代物。加鎖用于保證數(shù)據(jù)結(jié)構(gòu)的完整性,而引用
          計數(shù)是一個內(nèi)存管理技術(shù)。通常你兩個都需要,不應該有任何混淆不清的地方。

          一些數(shù)據(jù)結(jié)構(gòu)可能使用兩層的引用計數(shù),當對不同的“類”都有使用的時候。子
          類的計數(shù)統(tǒng)計所有子類用戶的數(shù)目,當子類的計數(shù)為零時只對總計數(shù)減一。

          這種“多層引用計數(shù)”的例子可以在內(nèi)存管理代碼(“struct
          mm_struct”:
          mm_users和mm_cout)和文件系統(tǒng)代碼(“struct
          super_block”:s_count和
          s_active)中找到。

          記住:如果另一個線程能夠看見你的數(shù)據(jù)結(jié)構(gòu),而你卻沒有對它使用引用計數(shù),
          那么幾乎可以肯定會有bug存在。

          posted on 2005-12-02 13:14 ivaneeo 閱讀(605) 評論(0)  編輯  收藏 所屬分類: GNU牛力
          主站蜘蛛池模板: 河东区| 内黄县| 高邑县| 莒南县| 绥宁县| 安庆市| 九寨沟县| 古交市| 团风县| 陆良县| 三台县| 巴里| 晋城| 乾安县| 崇文区| 财经| 敦煌市| 九龙县| 定陶县| 新建县| 枣强县| 乌鲁木齐县| 栾城县| 思茅市| 铜陵市| 林芝县| 内乡县| 乌什县| 武汉市| 稷山县| 铜陵市| 长沙市| 清原| 乡宁县| 洛阳市| 虞城县| 惠州市| 米易县| 丰顺县| 茶陵县| 文登市|