日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux内核编码风格

發布時間:2025/3/21 linux 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux内核编码风格 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

快速鏈接:
.
👉👉👉 個人博客筆記導讀目錄(全部) 👈👈👈


說明:
在默認情況下,本文講述的都是ARMV8-aarch64架構,linux kernel 5.14

Linux內核編碼風格
這是一個簡短的文檔,描述了 linux 內核的首選編碼風格。

1、 縮進

  • 制表符是 8 個字符,因此縮進也是 8 個字符。單行長度的首選限制是 80個字符,超過 80 字符的語句應該被分成合理的塊

  • switch及其下屬case的標簽在同一列中

  • 不要在一行中放置多個作業

  • 在注釋、文檔和 Kconfig 之外,使用TAB作為縮進

  • 遠不要破壞用戶可見的字符串,例如 printk 消息

3、放置大括號和空格

大括號和空格的使用,這適用于所有非函數語句塊(if、switch、for、while、do).

  • sizeof、typeof、alignof 或 attribute 后的括號,不需要放空格

  • 在大多數二元和三元運算符周圍(兩側)使用一個空格(= + - < > * / % | & ^ <= >= == != ? :)

  • 一元運算符后沒有空格(& * + - ~ ! sizeof typeof alignof attribute defined)

4、 命名

  • C 是一種 Spartan 語言,您的命名約定應遵循此規則。不贊成大小寫混合的名稱.
  • 全局變量需要具有描述性名稱,如您有一個計算活躍用戶數的函數,您應該調用它count_active_users()或類似的函數, 而不應該調用它cntusr()。
  • 局部 變量名應該簡短,切中要害。如果你有一些隨機整數循環計數器,它可能應該被調用i。
  • 對于符號名稱和文檔,避免引入“主/從”(或獨立于“主”的“從”)和“黑名單/白名單”的新用法,
    “主/從”的推薦替代品是:
    ‘{primary,main} / {secondary,replica,subordinate}’ ‘{initiator,requester} / {target,responder}’ ‘{controller,host} / {device,worker,proxy}’ ‘leader / follower’ 'director / performer
    “黑名單/白名單”的推薦替代品是:
    ‘denylist / allowlist’ ‘blocklist / passlist’

5、 類型定義

請不要使用諸如vps_t. 將 typedef 用于結構和指針是錯誤的。當你看到一個

vps_t a;
在源代碼中,它是什么意思?相反,如果它說

struct virtual_container *a;
你實際上可以說出是什么a。

很多人認為 typedefs . 不是這樣。它們僅用于:help readability

完全不透明的對象(typedef 被主動用于隱藏 對象是什么)。

示例:pte_t等,您只能使用適當的訪問器函數訪問的不透明對象。

筆記

不透明,本身就不好。我們將它們用于 pte_t 等內容的原因是那里確實有絕對零可移植的可訪問信息。accessor functions

清除整數類型,其中抽象有助于避免混淆,無論是int還是long。

u8/u16/u32 是非常好的 typedef,盡管它們比這里更適合 (d) 類。

筆記

再次 - 這需要有一個原因。如果有 ,那就沒有理由去做unsigned long

typedef unsigned long myflags_t;

但是如果有一個明確的理由說明為什么它在某些情況下可能是 an而在其他配置下可能是 ,那么請務必繼續使用 typedef。unsigned intunsigned long

當您使用 sparse 從字面上創建用于類型檢查的新類型時。

在某些特殊情況下與標準 C99 類型相同的新類型。

雖然眼睛和大腦只需要很短的時間就可以適應像 那樣的標準類型uint32_t,但還是有人反對使用它們。

因此,u8/u16/u32/u64允許使用特定于 Linux 的類型及其與標準類型相同的帶符號的等效項——盡管它們在您自己的新代碼中不是強制性的。

在編輯已經使用一個或另一組類型的現有代碼時,您應該符合該代碼中的現有選擇。

在用戶空間中安全使用的類型。

在用戶空間可見的某些結構中,我們不能要求 C99 類型,也不能使用u32上面的形式。因此,我們在與用戶空間共享的所有結構中使用 __u32 和類似類型。

也許還有其他情況,但規則基本上應該是永遠不要使用 typedef,除非您可以清楚地匹配這些規則之一。

通常,指針或具有可以合理直接訪問的元素的結構永遠不應該是 typedef。

6、 函數

函數應該短小精悍,只做一件事。它們應該適合一兩屏文本(ISO/ANSI 屏幕尺寸是 80x24,眾所周知),并且做一件事并且做得好。

函數的最大長度與該函數的復雜性和縮進級別成反比。所以,如果你有一個概念上簡單的函數,它只是一個長(但簡單)的 case 語句,你必須為很多不同的情況做很多小事情,那么有一個更長的函數是可以的。

但是,如果您有一個復雜的函數,并且您懷疑一個沒有天賦的高中一年級學生甚至可能不了解該函數的全部內容,那么您應該更加嚴格地遵守最大限制。使用具有描述性名稱的輔助函數(如果您認為它對性能至關重要,您可以要求編譯器將它們內聯,并且它可能會比您做得更好)。

函數的另一個度量是局部變量的數量。他們不應該超過 5-10,否則你做錯了什么。重新思考這個功能,把它分成更小的部分。人腦通常可以輕松地跟蹤大約 7 種不同的事物,如果再多一些,就會感到困惑。您知道自己很出色,但也許您想了解 2 周后您做了什么。

在源文件中,用一個空行分隔函數。如果函數被導出,它的EXPORT宏應該緊跟在函數結束括號之后。例如:

int system_is_up(void)
{
return system_state == SYSTEM_RUNNING;
}
EXPORT_SYMBOL(system_is_up);
6.1) 函數原型
在函數原型中,包括參數名稱及其數據類型。雖然這不是 C 語言所要求的,但它在 Linux 中是首選,因為它是一種為讀者添加有價值信息的簡單方法。

不要在extern函數聲明中使用關鍵字,因為這會使行變長并且不是絕對必要的。

在編寫函數原型時,請保持元素的順序規則。例如,使用這個函數聲明示例:

__init void * __must_check action(enum magic value, size_t size, u8 count,
char *fmt, …) __printf(4, 5) __malloc;
函數原型的首選元素順序是:

存儲類(下面,,請注意, 從技術上講,這是一個屬性,但被視為)static __always_inline__always_inlineinline

存儲類屬性(這里,__init-即節聲明,還有類似的東西__cold)

返回類型(這里,)void *

返回類型屬性(此處為__must_check)

函數名(這里,action)

函數參數(此處為 ,注意應始終包含參數名稱)(enum magic value, size_t size, u8 count, char *fmt, …)

函數參數屬性(這里,)__printf(4, 5)

函數行為屬性(此處,__malloc)

注意對于一個函數定義(即實際的函數體),編譯器不允許在函數參數之后有函數參數屬性。在這些情況下,它們應該在存儲類屬性之后(例如 ,與上面的聲明示例相比,請注意下面的更改位置):__printf(4, 5)

static __always_inline __init __printf(4, 5) void * __must_check action(enum magic value,
size_t size, u8 count, char *fmt, …) __malloc
{

}

7、 功能集中退出

盡管有些人不贊成,但編譯器經常以無條件跳轉指令的形式使用 goto 語句的等效項。

當一個函數從多個位置退出并且必須完成一些諸如清理之類的常見工作時,goto 語句就派上用場了。如果不需要清理,則直接返回。

選擇標簽名稱,說明 goto 的作用或 goto 存在的原因。一個好名字的例子可能是out_free_buffer:如果 goto 釋放buffer. 避免使用 GW-BASIC 名稱err1:和err2:,因為如果您添加或刪除出口路徑,您將不得不重新編號它們,并且它們無論如何都難以驗證正確性。

使用 goto 的基本原理是:

無條件語句更容易理解和遵循

嵌套減少

防止在進行修改時不更新各個出口點而導致的錯誤

節省編譯器的工作以優化冗余代碼;)

int fun(int a)
{
int result = 0;
char *buffer;

buffer = kmalloc(SIZE, GFP_KERNEL);if (!buffer)return -ENOMEM;if (condition1) {while (loop1) {...}result = 1;goto out_free_buffer;}...

out_free_buffer:
kfree(buffer);
return result;
}
需要注意的一種常見錯誤類型如下所示:one err bugs

err:
kfree(foo->bar);
kfree(foo);
return ret;
此代碼中的錯誤是在某些退出路徑上foo為 NULL。通常對此的解決方法是將其分成兩個錯誤標簽err_free_bar:和 err_free_foo::

err_free_bar:
kfree(foo->bar);
err_free_foo:
kfree(foo);
return ret;
理想情況下,您應該模擬錯誤以測試所有退出路徑。

8、 評論

評論是好的,但也有過度評論的危險。永遠不要試圖在注釋中解釋你的代碼是如何工作的:編寫代碼以便工作是顯而易見的要好得多,而解釋寫得不好的代碼是浪費時間。

通常,您希望您的注釋說明您的代碼做了什么,而不是如何做。另外,盡量避免在函數體中放置注釋:如果函數太復雜以至于你需要單獨注釋它的一部分,你可能應該回到第 6 章一段時間。你可以做一些小的評論來注意或警告一些特別聰明(或丑陋)的東西,但盡量避免過度。相反,將注釋放在函數的開頭,告訴人們它做了什么,以及它為什么這樣做。

注釋內核 API 函數時,請使用 kernel-doc 格式。看到這些文件在文件/文件引導/并 scripts/kernel-doc了解詳情。

長(多行)注釋的首選樣式是:

/*

  • This is the preferred style for multi-line
  • comments in the Linux kernel source code.
  • Please use it consistently.
  • Description: A column of asterisks on the left side,
  • with beginning and ending almost-blank lines.
    */
    對于 net/ 和 drivers/net/ 中的文件,長(多行)注釋的首選樣式略有不同。

/* The preferred comment style for files in net/ and drivers/net

  • looks like this.
  • It is nearly the same as the generally preferred comment style,
  • but there is no initial almost-blank line.
    */
    注釋數據也很重要,無論它們是基本類型還是派生類型。為此,每行只使用一個數據聲明(多個數據聲明沒有逗號)。這樣您就可以對每個項目進行簡短的評論,解釋其用途。

9、你把它弄得一團糟

沒關系,我們都這樣。您的長期 Unix 用戶助手可能已經告訴您,它會自動為您格式化 C 源代碼,并且您已經注意到是的,它確實這樣做了,但是它使用的默認值并不理想(事實上,它們比隨機輸入更糟糕——無數的猴子輸入 GNU emacs 永遠不會成為一個好的程序)。GNU emacs

因此,您可以擺脫 GNU emacs,或將其更改為使用更合理的值。要執行后者,您可以在 .emacs 文件中粘貼以下內容:

(defun c-lineup-arglist-tabs-only (ignored)
“Line up argument lists by tabs, not spaces”
(let* ((anchor (c-langelem-pos c-syntactic-element))
(column (c-langelem-2nd-pos c-syntactic-element))
(offset (- (1+ column) anchor))
(steps (floor offset c-basic-offset)))
(* (max steps 1)
c-basic-offset)))

(dir-locals-set-class-variables
'linux-kernel
'((c-mode . (
(c-basic-offset . 8)
(c-label-minimum-indentation . 0)
(c-offsets-alist . (
(arglist-close . c-lineup-arglist-tabs-only)
(arglist-cont-nonempty .
(c-lineup-gcc-asm-reg c-lineup-arglist-tabs-only))
(arglist-intro . +)
(brace-list-intro . +)
(c . c-lineup-C-comments)
(case-label . 0)
(comment-intro . c-lineup-comment)
(cpp-define-intro . +)
(cpp-macro . -1000)
(cpp-macro-cont . +)
(defun-block-intro . +)
(else-clause . 0)
(func-decl-cont . +)
(inclass . +)
(inher-cont . c-lineup-multi-inher)
(knr-argdecl-intro . 0)
(label . -1000)
(statement . 0)
(statement-block-intro . +)
(statement-case-intro . +)
(statement-cont . +)
(substatement . +)
))
(indent-tabs-mode . t)
(show-trailing-whitespace . t)
))))

(dir-locals-set-directory-class
(expand-file-name “~/src/linux-trees”)
'linux-kernel)
這將使 emacs 更好地使用下面 C 文件的內核編碼風格~/src/linux-trees。

但是,即使您未能讓 emacs 進行合理的格式化,也并非一切都會丟失:使用indent.

現在,再次重申,GNU 縮進具有與 GNU emacs 相同的腦死設置,這就是為什么您需要為其提供一些命令行選項的原因。然而,這還不算太糟糕,因為即使是 GNU indent 的制造者也承認 K&R 的權威(GNU 人并不邪惡,他們只是在這件事上被嚴重誤導了),所以你只需給 indent 選項(代表),或使用 ,以最新樣式縮進。-kr -i8K&R, 8 character indentsscripts/Lindent

indent有很多選項,尤其是在評論重新格式化時,您可能需要查看手冊頁。但請記住:indent這不是對糟糕編程的修復。

請注意,您還可以使用該clang-format工具來幫助您處理這些規則,自動快速重新格式化部分代碼,并查看完整文件以發現編碼風格錯誤、拼寫錯誤和可能的改進。它對于排序#includes、對齊變量/宏、重排文本和其他類似任務也很方便。查看文件clang-format 了解更多詳情。

10、Kconfig配置文件

對于整個源代碼樹中的所有 Kconfig* 配置文件,縮進都有些不同。config定義下的行縮進一個制表符,而幫助文本縮進兩個空格。例子:

config AUDIT
bool “Auditing support”
depends on NET
help
Enable auditing infrastructure that can be used with another
kernel subsystem, such as SELinux (which requires this for
logging of avc messages output). Does not do system-call
auditing without CONFIG_AUDITSYSCALL.
嚴重危險的功能(例如對某些文件系統的寫支持)應該在其提示字符串中突出顯示這一點:

config ADFS_FS_RW
bool “ADFS write support (DANGEROUS)”
depends on ADFS_FS

有關配置文件的完整文檔,請參閱文件 Kconfig Language。

11、數據結構

在創建和銷毀它們的單線程環境之外具有可見性的數據結構應該始終具有引用計數。在內核中,垃圾收集不存在(并且在內核之外垃圾收集緩慢且低效),這意味著您絕對必須對所有使用進行引用計數。

引用計數意味著您可以避免鎖定,并允許多個用戶并行訪問數據結構——而不必擔心結構突然從他們下面消失,因為他們睡了一段時間或做了其他事情。

注意,鎖不是引用計數的替代品。鎖定用于保持數據結構的一致性,而引用計數是一種內存管理技術。通常兩者都需要,并且不要將它們相互混淆。

許多數據結構確實可以有兩個級別的引用計數,當存在不同的classes. 子類計數計算子類用戶的數量,當子類計數變為零時,只減少一次全局計數。

此類示例multi-level-reference-counting可以在內存管理(:mm_users 和 mm_count)和文件系統代碼(:s_count 和 s_active)中找到。struct mm_structstruct super_block

請記住:如果另一個線程可以找到您的數據結構,而您沒有引用計數,那么您幾乎肯定有錯誤。

12)、宏、枚舉和 RTL

在枚舉中定義常量和標簽的宏的名稱大寫。

#define CONSTANT 0x12345
定義多個相關常量時,首選枚舉。

大寫的宏名稱值得贊賞,但類似函數的宏可能以小寫命名。

通常,內聯函數比類似函數的宏更可取。

包含多個語句的宏應該包含在 do - while 塊中:

#define macrofun(a, b, c)
do {
if (a == 5)
do_this(b, c);
} while (0)
使用宏時要避免的事情:

影響控制流的宏:

#define FOO(x)
do {
if (blah(x) < 0)
return -EBUGGERED;
} while (0)
是一個非常糟糕的主意。它看起來像一個函數調用但退出了calling 函數;不要破壞那些將閱讀代碼的人的內部解析器。

依賴于具有魔法名稱的局部變量的宏:

#define FOO(val) bar(index, val)
可能看起來是件好事,但是當人們閱讀代碼時它會令人困惑,而且它很容易因看似無害的更改而損壞。

  • 帶有用作左值的參數的宏:FOO(x) = y;如果有人將 FOO 轉換為內聯函數,則會咬你。

  • 忘記優先級:使用表達式定義常量的宏必須將表達式括在括號中。請注意使用參數的宏的類似問題。

  • #define CONSTANT 0x4000
    #define CONSTEXP (CONSTANT | 3)
    5) 在類似函數的宏中定義局部變量時的命名空間沖突:

    #define FOO(x)
    ({
    typeof(x) ret;
    ret = calc_ret(x);
    (ret);
    })
    ret 是局部變量的通用名稱 - __foo_ret 不太可能與現有變量發生沖突。

    cpp 手冊詳盡地處理了宏。gcc 內部手冊還涵蓋了內核中經常與匯編語言一起使用的 RTL。

    13、 打印內核消息

    內核開發人員喜歡被視為有文化的人。請注意內核消息的拼寫以給人留下好印象。不要使用不正確的收縮,如dont; 使用或代替。使信息簡潔、清晰、不含糊。do notdon’t

    內核消息不必以句點終止。

    在括號 (%d) 中打印數字不會增加任何值,應避免使用。

    <linux/dev_printk.h> 中有許多驅動程序模型診斷宏,您應該使用它們來確保消息與正確的設備和驅動程序匹配,并使用正確的級別進行標記:dev_err()、dev_warn()、 dev_info() 等等。對于沒有與特定設備,在<linux / printk.h>定義相關聯的消息pr_notice(),pr_info(), pr_warn(),pr_err(),等。

    想出好的調試消息可能是一個很大的挑戰。一旦擁有它們,它們就可以為遠程故障排除提供巨大幫助。然而,調試消息打印的處理方式與打印其他非調試消息不同。雖然其他 pr_XXX() 函數無條件打印, pr_debug()但不會;它默認被編譯出來,除非定義了 DEBUG 或設置了 CONFIG_DYNAMIC_DEBUG。對于 dev_dbg() 也是如此,相關約定使用 VERBOSE_DEBUG 將 dev_vdbg() 消息添加到已由 DEBUG 啟用的消息中。

    許多子系統都有 Kconfig 調試選項,可以在對應的 Makefile 中開啟 -DDEBUG;在其他情況下,特定文件#define DEBUG。當應該無條件打印調試消息時,例如如果它已經在調試相關的#ifdef 部分中,則可以使用 printk(KERN_DEBUG …)。

    14、分配內存

    內核提供了以下通用的內存分配: kmalloc(),kzalloc(),kmalloc_array(),kcalloc(),vmalloc(),和 vzalloc()。有關它們的更多信息,請參閱 API 文檔。 內存分配指南

    傳遞結構大小的首選形式如下:

    p = kmalloc(sizeof(*p), …);
    當指針變量類型更改但傳遞給內存分配器的相應 sizeof 未更改時,拼寫結構名稱的替代形式會損害可讀性并引入錯誤的機會。

    強制轉換為空指針的返回值是多余的。C 編程語言保證了從 void 指針到任何其他指針類型的轉換。

    分配數組的首選形式如下:

    p = kmalloc_array(n, sizeof(…), …);
    分配歸零數組的首選形式如下:

    p = kcalloc(n, sizeof(…), …);
    兩種形式都檢查分配大小 n * sizeof(…) 上的溢出,如果發生則返回 NULL。

    這些通用分配函數在沒有 __GFP_NOWARN 的情況下使用時都會在失敗時發出堆棧轉儲,因此在返回 NULL 時發出額外的失敗消息是沒有用的。

    15 、內聯

    似乎有一個普遍的誤解,即 gcc 有一個神奇的“讓我更快”的加速選項,稱為inline. 雖然內聯的使用可能是合適的(例如作為替換宏的方法,參見第 12 章),但通常不是。大量使用 inline 關鍵字會導致更大的內核,這反過來又會降低整個系統的速度,因為 CPU 的 icache 占用空間更大,而且頁面緩存可用的內存更少。考慮一下; 頁面緩存未命中會導致磁盤搜索,這很容易花費 5 毫秒。有很多 cpu 周期可以進入這 5 毫秒。

    一個合理的經驗法則是不要將內聯放在包含超過 3 行代碼的函數中。此規則的一個例外是參數已知為編譯時常量的情況,并且由于此常量,您知道編譯器將能夠在編譯時優化大部分函數。有關后面這種情況的一個很好的例子,請參閱kmalloc()內聯函數。

    人們經常爭辯說,向靜態且僅使用一次的函數添加內聯總是一種勝利,因為沒有空間權衡。雖然這在技術上是正確的,但 gcc 能夠在沒有幫助的情況下自動內聯這些,并且當第二個用戶出現時刪除內聯的維護問題超過了告訴 gcc 做一些它無論如何都會做的事情的提示的潛在價值。

    16、函數返回值和名稱

    函數可以返回多種不同類型的值,最常見的一種是指示函數是成功還是失敗的值。這樣的值可以表示為錯誤代碼整數(-Exxx = 失敗,0 = 成功)或succeeded布爾值(0 = 失敗,非零 = 成功)。

    混合這兩種表示是難以發現的錯誤的肥沃來源。如果 C 語言包含整數和布爾值之間的明顯區別,那么編譯器會為我們發現這些錯誤……但它沒有。為了幫助防止此類錯誤,請始終遵循以下約定:

    If the name of a function is an action or an imperative command,
    the function should return an error-code integer. If the name
    is a predicate, the function should return a “succeeded” boolean.
    例如,是一個命令,add_work() 函數返回 0 表示成功或 -EBUSY 表示失敗。同樣,是謂詞,如果成功找到匹配的設備,則函數返回 1,否則返回 0。add workPCI device presentpci_dev_present()

    所有導出的函數都必須遵守這個約定,所有公共函數也應該如此。私有(靜態)函數不需要,但建議他們這樣做。

    返回值是計算的實際結果而不是計算是否成功的指示的函數不受此規則的約束。通常,它們通過返回一些超出范圍的結果來指示失敗。典型的例子是返回指針的函數;他們使用 NULL 或 ERR_PTR 機制來報告失敗。

    17、 使用布爾值

    Linux 內核 bool 類型是 C99 _Bool 類型的別名。bool 值只能計算為 0 或 1,隱式或顯式轉換為 bool 會自動將值轉換為 true 或 false。使用 bool 類型時 !! 不需要構造,這就消除了一類錯誤。

    使用 bool 值時,應使用 true 和 false 定義而不是 1 和 0。

    bool 函數返回類型和堆棧變量總是可以在適當的時候使用。鼓勵使用 bool 來提高可讀性,并且對于存儲布爾值通常是比 ‘int’ 更好的選擇。

    如果緩存行布局或值的大小很重要,請不要使用 bool,因為它的大小和對齊方式根據編譯的架構而變化。針對對齊和大小優化的結構不應使用 bool。

    如果結構具有許多真/假值,請考慮將它們合并為一個具有 1 位成員的位域,或使用適當的固定寬度類型,例如 u8。

    類似地,對于函數參數,許多真/假值可以合并為單個按位“標志”參數,如果調用站點具有裸真/假常量,“標志”通常可以是更具可讀性的替代方案。

    否則,在結構和參數中有限使用 bool 可以提高可讀性。

    18、不要重新發明內核宏

    頭文件 include/linux/kernel.h 包含許多您應該使用的宏,而不是自己明確編碼它們的某些變體。例如,如果您需要計算數組的長度,請利用宏

    #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
    同樣,如果您需要計算某個結構成員的大小,請使用

    #define sizeof_field(t, f) (sizeof(((t*)0)->f))
    如果需要,還有 min() 和 max() 宏可以進行嚴格的類型檢查。隨意仔細閱讀該頭文件以查看已經定義的其他內容,您不應該在代碼中重現。

    19、編輯器模式和其他雜物

    一些編輯器可以解釋嵌入在源文件中的配置信息,用特殊標記表示。例如,emacs 解釋如下標記的行:

    -- mode: c --
    或者像這樣:

    /*
    Local Variables:
    compile-command: “gcc -DMAGIC_DEBUG_FLAG foo.c”
    End:
    */
    Vim 解釋如下標記:

    /* vim:set sw=8 noet */
    不要在源文件中包含任何這些。人們有自己的個人編輯器配置,您的源文件不應覆蓋它們。這包括用于縮進和模式配置的標記。人們可能會使用他們自己的自定義模式,或者可能有一些其他神奇的方法來使縮進正常工作。

  • 內聯組裝
    在特定于體系結構的代碼中,您可能需要使用內聯匯編來與 CPU 或平臺功能交互。必要時不要猶豫,這樣做。但是,當 C 可以完成這項工作時,不要無緣無故地使用內聯匯編。如果可能,您可以并且應該從 C 中插入硬件。
  • 考慮編寫簡單的輔助函數來包裝內聯匯編的常見位,而不是重復編寫帶有細微變化的它們。請記住,內聯匯編可以使用 C 參數。

    大型的、非平凡的匯編函數應該放在 .S 文件中,并在 C 頭文件中定義相應的 C 原型。匯編函數的 C 原型應該使用asmlinkage.

    您可能需要將 asm 語句標記為 volatile,以防止 GCC 在 GCC 沒有注意到任何副作用時將其刪除。但是,您并不總是需要這樣做,并且不必要地這樣做會限制優化。

    在編寫包含多條指令的單個內聯匯編語句時,將每條指令放在單獨的一行中單獨的帶引號的字符串中,并結束除最后一個字符串之外的每個字符串\n\t以在匯編輸出中正確縮進下一條指令:

    asm (“magic %reg1, #42\n\t”
    “more_magic %reg2, %reg3”
    : /* outputs / : / inputs / : / clobbers */);
    21) 條件編譯
    在可能的情況下,不要在 .c 文件中使用預處理器條件(#if、#ifdef);這樣做會使代碼更難閱讀,邏輯更難遵循。相反,在定義用于那些 .c 文件的函數的頭文件中使用此類條件,在 #else 情況下提供無操作存根版本,然后從 .c 文件無條件調用這些函數。編譯器將避免為存根調用生成任何代碼,產生相同的結果,但邏輯仍將易于遵循。

    更喜歡編譯整個函數,而不是部分函數或部分表達式。與其將 ifdef 放入表達式中,不如將部分或全部表達式分解為單獨的輔助函數并將條件應用于該函數。

    如果您有一個函數或變量可能在特定配置中未使用,并且編譯器會警告其定義未使用,請將定義標記為 __maybe_unused 而不是將其包裝在預處理器條件中。(但是,如果函數或變量總是未使用,請將其刪除。)

    在代碼中,在可能的情況下,使用 IS_ENABLED 宏將 Kconfig 符號轉換為 C 布爾表達式,并在普通 C 條件中使用它:

    if (IS_ENABLED(CONFIG_SOMETHING)) {

    }
    編譯器會將條件折疊起來,并像#ifdef 一樣包含或排除代碼塊,因此這不會增加任何運行時開銷。但是,這種方法仍然允許 C 編譯器查看塊內的代碼,并檢查它的正確性(語法、類型、符號引用等)。因此,如果塊內的代碼引用了不滿足條件時將不存在的符號,則您仍然必須使用 #ifdef。

    在任何非平凡的#if 或#ifdef 塊(多于幾行)的末尾,在同一行的#endif 之后放置一個注釋,注意使用的條件表達式。例如:

    #ifdef CONFIG_SOMETHING

    #endif /* CONFIG_SOMETHING */
    附錄一)參

    總結

    以上是生活随笔為你收集整理的Linux内核编码风格的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。