.. include:: ../disclaimer-zh_CN.rst :Original: Documentation/process/coding-style.rst .. _cn_codingstyle: :译者: - å¼ ä¹ Zhang Le <r0bertz@gentoo.org> - Andy Deng <theandy.deng@gmail.com> - å´æƒ³æˆ <bobwxc@email.cn> :æ ¡è¯‘: - çŽ‹èª Wang Cong <xiyou.wangcong@gmail.com> - wheelz <kernel.zeng@gmail.com> - 管æ—东 Xudong Guan <xudong.guan@gmail.com> - Li Zefan <lizf@cn.fujitsu.com> - Wang Chen <wangchen@cn.fujitsu.com> Linux å†…æ ¸ä»£ç é£Žæ ¼ ================== 这是一个简çŸçš„文档,æ述了 linux å†…æ ¸çš„é¦–é€‰ä»£ç é£Žæ ¼ã€‚ä»£ç é£Žæ ¼æ˜¯å› äººè€Œå¼‚çš„ï¼Œ 而且我ä¸æ„¿æ„æŠŠè‡ªå·±çš„è§‚ç‚¹å¼ºåŠ ç»™ä»»ä½•äººï¼Œä½†è¿™å°±åƒæˆ‘去åšä»»ä½•äº‹æƒ…都必须éµå¾ªçš„原则 é‚£æ ·ï¼Œæˆ‘ä¹Ÿå¸Œæœ›åœ¨ç»å¤§å¤šæ•°äº‹ä¸Šä¿æŒè¿™ç§çš„æ€åº¦ã€‚请 (在写代ç æ—¶) 至少考虑一下这里 的代ç é£Žæ ¼ã€‚ é¦–å…ˆï¼Œæˆ‘å»ºè®®ä½ æ‰“å°ä¸€ä»½ GNU 代ç 规范,然åŽä¸è¦è¯»ã€‚烧了它,这是一个具有é‡å¤§è±¡å¾ 性æ„义的动作。 ä¸ç®¡æ€Žæ ·ï¼ŒçŽ°åœ¨æˆ‘们开始: 1) 缩进 ------- 制表符是 8 个å—符,所以缩进也是 8 个å—符。有些异端è¿åŠ¨è¯•å›¾å°†ç¼©è¿›å˜ä¸º 4 (甚至 2ï¼) å—ç¬¦æ·±ï¼Œè¿™å‡ ä¹Žç›¸å½“äºŽå°è¯•å°†åœ†å‘¨çŽ‡çš„值定义为 3。 ç†ç”±ï¼šç¼©è¿›çš„全部æ„义就在于清楚的定义一个控制å—èµ·æ¢äºŽä½•å¤„ã€‚å°¤å…¶æ˜¯å½“ä½ ç›¯ç€ä½ çš„ å±å¹•è¿žç»çœ‹äº† 20 å°æ—¶ä¹‹åŽï¼Œä½ 将会å‘çŽ°å¤§ä¸€ç‚¹çš„ç¼©è¿›ä¼šä½¿ä½ æ›´å®¹æ˜“åˆ†è¾¨ç¼©è¿›ã€‚ 现在,有些人会抱怨 8 个å—符的缩进会使代ç å‘å³è¾¹ç§»åŠ¨çš„太远,在 80 个å—符的终端 å±å¹•ä¸Šå°±å¾ˆéš¾è¯»è¿™æ ·çš„代ç 。这个问题的ç”æ¡ˆæ˜¯ï¼Œå¦‚æžœä½ éœ€è¦ 3 级以上的缩进,ä¸ç®¡ç”¨ 何ç§æ–¹å¼ä½ 的代ç å·²ç»æœ‰é—®é¢˜äº†ï¼Œåº”该修æ£ä½ 的程åºã€‚ 简而言之,8 个å—符的缩进å¯ä»¥è®©ä»£ç æ›´å®¹æ˜“é˜…è¯»ï¼Œè¿˜æœ‰ä¸€ä¸ªå¥½å¤„æ˜¯å½“ä½ çš„å‡½æ•°åµŒå¥—å¤ª 深的时候å¯ä»¥ç»™ä½ è¦å‘Šã€‚留心这个è¦å‘Šã€‚ 在 switch è¯å¥ä¸æ¶ˆé™¤å¤šçº§ç¼©è¿›çš„首选的方å¼æ˜¯è®© ``switch`` 和从属于它的 ``case`` æ ‡ç¾å¯¹é½äºŽåŒä¸€åˆ—,而ä¸è¦ ``两次缩进`` ``case`` æ ‡ç¾ã€‚比如: .. code-block:: c switch (suffix) { case 'G': case 'g': mem <<= 30; break; case 'M': case 'm': mem <<= 20; break; case 'K': case 'k': mem <<= 10; fallthrough; default: break; } ä¸è¦æŠŠå¤šä¸ªè¯å¥æ”¾åœ¨ä¸€è¡Œé‡Œï¼Œé™¤éžä½ 有什么东西è¦éšè—: .. code-block:: c if (condition) do_this; do_something_everytime; ä¸è¦ä½¿ç”¨é€—å·æ¥é¿å…使用大括å·ï¼š .. code-block:: c if (condition) do_this(), do_that(); 使用大括å·åŒ…裹多è¯å¥ï¼š .. code-block:: c if (condition) { do_this(); do_that(); } 也ä¸è¦åœ¨ä¸€è¡Œé‡Œæ”¾å¤šä¸ªèµ‹å€¼è¯å¥ã€‚å†…æ ¸ä»£ç é£Žæ ¼è¶…çº§ç®€å•ã€‚就是é¿å…å¯èƒ½å¯¼è‡´åˆ«äººè¯¯è¯» 的表达å¼ã€‚ 除了注释ã€æ–‡æ¡£å’Œ Kconfig 之外,ä¸è¦ä½¿ç”¨ç©ºæ ¼æ¥ç¼©è¿›ï¼Œå‰é¢çš„例å是例外,是有æ„为 之。 选用一个好的编辑器,ä¸è¦åœ¨è¡Œå°¾ç•™ç©ºæ ¼ã€‚ 2) 把长的行和å—符串打散 ----------------------- 代ç é£Žæ ¼çš„æ„义就在于使用平常使用的工具æ¥ç»´æŒä»£ç çš„å¯è¯»æ€§å’Œå¯ç»´æŠ¤æ€§ã€‚ æ¯ä¸€è¡Œçš„长度的é™åˆ¶æ˜¯ 80 列,我们强烈建议您éµå®ˆè¿™ä¸ªæƒ¯ä¾‹ã€‚ 长于 80 列的è¯å¥è¦æ‰“æ•£æˆæœ‰æ„义的片段。除éžè¶…过 80 åˆ—èƒ½æ˜¾è‘—å¢žåŠ å¯è¯»æ€§ï¼Œå¹¶ä¸”ä¸ ä¼šéšè—ä¿¡æ¯ã€‚ å片段è¦æ˜Žæ˜¾çŸäºŽæ¯ç‰‡æ®µï¼Œå¹¶æ˜Žæ˜¾é å³ã€‚一ç§éžå¸¸å¸¸ç”¨çš„æ ·å¼æ˜¯å°†å体与函数左括å·å¯¹é½ã€‚ è¿™åŒæ ·é€‚用于有ç€å¾ˆé•¿å‚数列表的函数头。 然而,ç»å¯¹ä¸è¦æ‰“散对用户å¯è§çš„å—符串,例如 printk ä¿¡æ¯ï¼Œå› ä¸ºè¿™æ ·å°± 很难对它们 grep。 3) 大括å·å’Œç©ºæ ¼çš„放置 --------------------- C è¯è¨€é£Žæ ¼ä¸å¦å¤–一个常è§é—®é¢˜æ˜¯å¤§æ‹¬å·çš„放置。和缩进大å°ä¸åŒï¼Œé€‰æ‹©æˆ–弃用æŸç§æ”¾ ç½®ç–ç•¥å¹¶æ²¡æœ‰å¤šå°‘æŠ€æœ¯ä¸Šçš„åŽŸå› ï¼Œä¸è¿‡é¦–选的方å¼ï¼Œå°±åƒ Kernighan å’Œ Ritchie 展示 给我们的,是把起始大括å·æ”¾åœ¨è¡Œå°¾ï¼Œè€ŒæŠŠç»“æŸå¤§æ‹¬å·æ”¾åœ¨è¡Œé¦–,所以: .. code-block:: c if (x is true) { we do y } 这适用于所有的éžå‡½æ•°è¯å¥å— (if, switch, for, while, do)。比如: .. code-block:: c switch (action) { case KOBJ_ADD: return "add"; case KOBJ_REMOVE: return "remove"; case KOBJ_CHANGE: return "change"; default: return NULL; } ä¸è¿‡ï¼Œæœ‰ä¸€ä¸ªä¾‹å¤–,那就是函数:函数的起始大括å·æ”¾ç½®äºŽä¸‹ä¸€è¡Œçš„开头,所以: .. code-block:: c int function(int x) { body of function } 全世界的异端å¯èƒ½ä¼šæŠ±æ€¨è¿™ä¸ªä¸ä¸€è‡´æ€§æ˜¯â€¦â€¦å‘ƒâ€¦â€¦ä¸ä¸€è‡´ï¼Œä¸è¿‡æ‰€æœ‰æ€ç»´å¥å…¨çš„人 éƒ½çŸ¥é“ (a) K&R 是 **æ£ç¡®çš„** 并且 (b) K&R 是æ£ç¡®çš„。æ¤å¤–,ä¸ç®¡æ€Žæ ·å‡½æ•°éƒ½æ˜¯ç‰¹ 殊的 (C 函数是ä¸èƒ½åµŒå¥—çš„)。 注æ„结æŸå¤§æ‹¬å·ç‹¬è‡ªå æ®ä¸€è¡Œï¼Œé™¤éžå®ƒåŽé¢è·Ÿç€åŒä¸€ä¸ªè¯å¥çš„剩余部分,也就是 do è¯ å¥ä¸çš„ ``while`` 或者 if è¯å¥ä¸çš„ ``else`` ,åƒè¿™æ ·ï¼š .. code-block:: c do { body of do-loop } while (condition); å’Œ .. code-block:: c if (x == y) { .. } else if (x > y) { ... } else { .... } ç†ç”±ï¼šK&R。 也请注æ„è¿™ç§å¤§æ‹¬å·çš„放置方å¼ä¹Ÿèƒ½ä½¿ç©º (或者差ä¸å¤šç©ºçš„) 行的数é‡æœ€å°åŒ–,åŒæ—¶ä¸ 失å¯è¯»æ€§ã€‚å› æ¤ï¼Œç”±äºŽä½ çš„å±å¹•ä¸Šçš„新行是ä¸å¯å†ç”Ÿèµ„æº (想想 25 行的终端å±å¹•)ï¼Œä½ å°†ä¼šæœ‰æ›´å¤šçš„ç©ºè¡Œæ¥æ”¾ç½®æ³¨é‡Šã€‚ 当åªæœ‰ä¸€ä¸ªå•ç‹¬çš„è¯å¥çš„时候,ä¸ç”¨åŠ ä¸å¿…è¦çš„大括å·ã€‚ .. code-block:: c if (condition) action(); å’Œ .. code-block:: c if (condition) do_this(); else do_that(); 这并ä¸é€‚用于åªæœ‰ä¸€ä¸ªæ¡ä»¶åˆ†æ”¯æ˜¯å•è¯å¥çš„情况;这时所有分支都è¦ä½¿ç”¨å¤§æ‹¬å·ï¼š .. code-block:: c if (condition) { do_this(); do_that(); } else { otherwise(); } 3.1) ç©ºæ ¼ ********* Linux å†…æ ¸çš„ç©ºæ ¼ä½¿ç”¨æ–¹å¼ (主è¦) å–决于它是用于函数还是关键å—。(大多数) å…³é”®å— åŽè¦åŠ ä¸€ä¸ªç©ºæ ¼ã€‚å€¼å¾—æ³¨æ„的例外是 sizeof, typeof, alignof å’Œ __attribute__,这 些关键å—æŸäº›ç¨‹åº¦ä¸Šçœ‹èµ·æ¥æ›´åƒå‡½æ•° (它们在 Linux 里也常常伴éšå°æ‹¬å·è€Œä½¿ç”¨ï¼Œå°½ç®¡ 在 C é‡Œè¿™æ ·çš„å°æ‹¬å·ä¸æ˜¯å¿…éœ€çš„ï¼Œå°±åƒ ``struct fileinfo info;`` 声明过åŽçš„ ``sizeof info``)。 所以在这些关键å—之åŽæ”¾ä¸€ä¸ªç©ºæ ¼:: if, switch, case, for, do, while 但是ä¸è¦åœ¨ sizeof, typeof, alignof 或者 __attribute__ 这些关键å—之åŽæ”¾ç©ºæ ¼ã€‚ 例如, .. code-block:: c s = sizeof(struct file); ä¸è¦åœ¨å°æ‹¬å·é‡Œçš„表达å¼ä¸¤ä¾§åŠ ç©ºæ ¼ã€‚è¿™æ˜¯ä¸€ä¸ª **å例** : .. code-block:: c s = sizeof( struct file ); 当声明指针类型或者返回指针类型的函数时, ``*`` 的首选使用方å¼æ˜¯ä½¿ä¹‹é è¿‘å˜é‡å 或者函数å,而ä¸æ˜¯é 近类型å。例å: .. code-block:: c char *linux_banner; unsigned long long memparse(char *ptr, char **retptr); char *match_strdup(substring_t *s); 在大多数二元和三元æ“ä½œç¬¦ä¸¤ä¾§ä½¿ç”¨ä¸€ä¸ªç©ºæ ¼ï¼Œä¾‹å¦‚ä¸‹é¢æ‰€æœ‰è¿™äº›æ“作符:: = + - < > * / % | & ^ <= >= == != ? : 但是一元æ“作符åŽä¸è¦åŠ ç©ºæ ¼:: & * + - ~ ! sizeof typeof alignof __attribute__ defined åŽç¼€è‡ªåŠ 和自å‡ä¸€å…ƒæ“作符å‰ä¸åŠ ç©ºæ ¼:: ++ -- å‰ç¼€è‡ªåŠ 和自å‡ä¸€å…ƒæ“作符åŽä¸åŠ ç©ºæ ¼:: ++ -- ``.`` å’Œ ``->`` 结构体æˆå‘˜æ“作符å‰åŽä¸åŠ ç©ºæ ¼ã€‚ ä¸è¦åœ¨è¡Œå°¾ç•™ç©ºç™½ã€‚有些å¯ä»¥è‡ªåŠ¨ç¼©è¿›çš„ç¼–è¾‘å™¨ä¼šåœ¨æ–°è¡Œçš„è¡Œé¦–åŠ å…¥é€‚é‡çš„ç©ºç™½ï¼Œç„¶åŽ ä½ å°±å¯ä»¥ç›´æŽ¥åœ¨é‚£ä¸€è¡Œè¾“入代ç 。ä¸è¿‡å‡å¦‚ä½ æœ€åŽæ²¡æœ‰åœ¨é‚£ä¸€è¡Œè¾“入代ç ,有些编辑器 å°±ä¸ä¼šç§»é™¤å·²ç»åŠ 入的空白,就åƒä½ æ•…æ„留下一个åªæœ‰ç©ºç™½çš„行。包å«è¡Œå°¾ç©ºç™½çš„行就 è¿™æ ·äº§ç”Ÿäº†ã€‚ 当 git å‘现补ä¸åŒ…å«äº†è¡Œå°¾ç©ºç™½çš„时候会è¦å‘Šä½ ,并且å¯ä»¥åº”ä½ çš„è¦æ±‚去掉行尾空白; ä¸è¿‡å¦‚æžœä½ æ˜¯æ£åœ¨æ‰“一系列补ä¸ï¼Œè¿™æ ·åšä¼šå¯¼è‡´åŽé¢çš„è¡¥ä¸å¤±è´¥ï¼Œå› ä¸ºä½ æ”¹å˜äº†è¡¥ä¸çš„ 上下文。 4) 命å ------- C 是一个简朴的è¯è¨€ï¼Œä½ 的命åä¹Ÿåº”è¯¥è¿™æ ·ã€‚å’Œ Modula-2 å’Œ Pascal 程åºå‘˜ä¸åŒï¼Œ C 程åºå‘˜ä¸ä½¿ç”¨ç±»ä¼¼ ThisVariableIsATemporaryCounter è¿™æ ·åŽä¸½çš„åå—。C 程åºå‘˜ä¼š 称那个å˜é‡ä¸º ``tmp`` ï¼Œè¿™æ ·å†™èµ·æ¥ä¼šæ›´å®¹æ˜“,而且至少ä¸ä¼šä»¤å…¶éš¾äºŽç†è§£ã€‚ ä¸è¿‡ï¼Œè™½ç„¶æ··ç”¨å¤§å°å†™çš„åå—是ä¸æ倡使用的,但是全局å˜é‡è¿˜æ˜¯éœ€è¦ä¸€ä¸ªå…·æ述性的 åå—。称一个全局函数为 ``foo`` 是一个难以饶æ•çš„错误。 全局å˜é‡ (åªæœ‰å½“ä½ **真æ£** 需è¦å®ƒä»¬çš„时候å†ç”¨å®ƒ) 需è¦æœ‰ä¸€ä¸ªå…·æ述性的åå—,就 åƒå…¨å±€å‡½æ•°ã€‚å¦‚æžœä½ æœ‰ä¸€ä¸ªå¯ä»¥è®¡ç®—活动用户数é‡çš„å‡½æ•°ï¼Œä½ åº”è¯¥å«å®ƒ ``count_active_users()`` 或者类似的åå—ï¼Œä½ ä¸åº”该å«å®ƒ ``cntuser()`` 。 在函数åä¸åŒ…å«å‡½æ•°ç±»åž‹ (所谓的匈牙利命å法) 是脑å出了问题——编译器知é“那些类 åž‹è€Œä¸”èƒ½å¤Ÿæ£€æŸ¥é‚£äº›ç±»åž‹ï¼Œè¿™æ ·åšåªèƒ½æŠŠç¨‹åºå‘˜å¼„糊涂了。 本地å˜é‡å应该简çŸï¼Œè€Œä¸”能够表达相关的å«ä¹‰ã€‚å¦‚æžœä½ æœ‰ä¸€äº›éšæœºçš„整数型的循环计 数器,它应该被称为 ``i`` 。å«å®ƒ ``loop_counter`` å¹¶æ— ç›Šå¤„ï¼Œå¦‚æžœå®ƒæ²¡æœ‰è¢«è¯¯è§£çš„ å¯èƒ½çš„è¯ã€‚类似的, ``tmp`` å¯ä»¥ç”¨æ¥ç§°å‘¼ä»»æ„类型的临时å˜é‡ã€‚ å¦‚æžœä½ æ€•æ··æ·†äº†ä½ çš„æœ¬åœ°å˜é‡åï¼Œä½ å°±é‡åˆ°å¦ä¸€ä¸ªé—®é¢˜äº†ï¼Œå«åšå‡½æ•°å¢žé•¿è·å°”蒙失衡综 åˆå¾ã€‚请看第å…ç« (函数)。 对于符å·å称和文档,é¿å…引入新的“master/slaveâ€ï¼ˆæˆ–独立于“masterâ€çš„“slaveâ€ï¼‰ 和“blacklist/whitelistâ€ã€‚ “master/slaveâ€æŽ¨è替æ¢ä¸ºï¼š '{primary,main} / {secondary,replica,subordinate}' '{initiator,requester} / {target,responder}' '{controller,host} / {device,worker,proxy}' 'leader/follower' 'director/performer' “blacklist/whitelistâ€æŽ¨è替æ¢ä¸ºï¼š 'denylist/allowlist' 'blocklist/passlist' 引入新用法的例外情况是:维护用户空间ABI/API,或更新现有(截至2020年)硬件或 å议规范的代ç æ—¶è¦æ±‚这些术è¯ã€‚对于新规范,尽å¯èƒ½å°†æœ¯è¯çš„规范用法转æ¢ä¸ºå†…æ ¸ ç¼–ç æ ‡å‡†ã€‚ .. warning:: 以上主从ã€é»‘白åå•è§„则ä¸é€‚用于ä¸æ–‡æ–‡æ¡£ï¼Œè¯·å‹¿æ›´æ”¹ä¸æ–‡æœ¯è¯ï¼ 5) Typedef ---------- ä¸è¦ä½¿ç”¨ç±»ä¼¼ ``vps_t`` 之类的东西。 对结构体和指针使用 typedef 是一个 **错误** ã€‚å½“ä½ åœ¨ä»£ç 里看到: .. code-block:: c vps_t a; 这代表什么æ„æ€å‘¢ï¼Ÿ 相åï¼Œå¦‚æžœæ˜¯è¿™æ · .. code-block:: c struct virtual_container *a; ä½ å°±çŸ¥é“ ``a`` 是什么了。 很多人认为 typedef ``能æ高å¯è¯»æ€§`` 。实际ä¸æ˜¯è¿™æ ·çš„。它们åªåœ¨ä¸‹åˆ—情况下有用: (a) 完全ä¸é€æ˜Žçš„对象 (è¿™ç§æƒ…况下è¦ä¸»åŠ¨ä½¿ç”¨ typedef æ¥ **éšè—** 这个对象实际上 是什么)。 例如: ``pte_t`` ç‰ä¸é€æ˜Žå¯¹è±¡ï¼Œä½ åªèƒ½ç”¨åˆé€‚的访问函数æ¥è®¿é—®å®ƒä»¬ã€‚ .. note:: ä¸é€æ˜Žæ€§å’Œâ€œè®¿é—®å‡½æ•°â€æœ¬èº«æ˜¯ä¸å¥½çš„。我们使用 pte_t ç‰ç±»åž‹çš„åŽŸå› åœ¨äºŽçœŸ 的是完全没有任何共用的å¯è®¿é—®ä¿¡æ¯ã€‚ (b) 清楚的整数类型,如æ¤ï¼Œè¿™å±‚抽象就å¯ä»¥ **帮助** 消除到底是 ``int`` 还是 ``long`` 的混淆。 u8/u16/u32 是完全没有问题的 typedef,ä¸è¿‡å®ƒä»¬æ›´ç¬¦åˆç±»åˆ« (d) 而ä¸æ˜¯è¿™é‡Œã€‚ .. note:: è¦è¿™æ ·åšï¼Œå¿…é¡»äº‹å‡ºæœ‰å› ã€‚å¦‚æžœæŸä¸ªå˜é‡æ˜¯ ``unsigned long`` ï¼Œé‚£ä¹ˆæ²¡æœ‰å¿…è¦ typedef unsigned long myflags_t; ä¸è¿‡å¦‚æžœæœ‰ä¸€ä¸ªæ˜Žç¡®çš„åŽŸå› ï¼Œæ¯”å¦‚å®ƒåœ¨æŸç§æƒ…况下å¯èƒ½ä¼šæ˜¯ä¸€ä¸ª ``unsigned int`` 而在其他情况下å¯èƒ½ä¸º ``unsigned long`` ,那么就ä¸è¦çŠ¹è±«ï¼Œè¯·åŠ¡å¿…使用 typedef。 (c) å½“ä½ ä½¿ç”¨ sparse 按å—é¢çš„创建一个 **æ–°** 类型æ¥åšç±»åž‹æ£€æŸ¥çš„时候。 (d) å’Œæ ‡å‡† C99 类型相åŒçš„类型,在æŸäº›ä¾‹å¤–的情况下。 虽然让眼ç›å’Œè„‘ç‹æ¥é€‚åº”æ–°çš„æ ‡å‡†ç±»åž‹æ¯”å¦‚ ``uint32_t`` ä¸éœ€è¦èŠ±å¾ˆå¤šæ—¶é—´ï¼Œå¯ 是有些人ä»ç„¶æ‹’ç»ä½¿ç”¨å®ƒä»¬ã€‚ å› æ¤ï¼ŒLinux 特有的ç‰åŒäºŽæ ‡å‡†ç±»åž‹çš„ ``u8/u16/u32/u64`` ç±»åž‹å’Œå®ƒä»¬çš„æœ‰ç¬¦å· ç±»åž‹æ˜¯è¢«å…è®¸çš„â€”â€”å°½ç®¡åœ¨ä½ è‡ªå·±çš„æ–°ä»£ç ä¸ï¼Œå®ƒä»¬ä¸æ˜¯å¼ºåˆ¶è¦æ±‚è¦ä½¿ç”¨çš„。 当编辑已ç»ä½¿ç”¨äº†æŸä¸ªç±»åž‹é›†çš„已有代ç æ—¶ï¼Œä½ åº”è¯¥éµå¾ªé‚£äº›ä»£ç ä¸å·²ç»åšå‡ºçš„选 择。 (e) å¯ä»¥åœ¨ç”¨æˆ·ç©ºé—´å®‰å…¨ä½¿ç”¨çš„类型。 在æŸäº›ç”¨æˆ·ç©ºé—´å¯è§çš„结构体里,我们ä¸èƒ½è¦æ±‚ C99 类型而且ä¸èƒ½ç”¨ä¸Šé¢æ到的 ``u32`` ç±»åž‹ã€‚å› æ¤ï¼Œæˆ‘们在与用户空间共享的所有结构体ä¸ä½¿ç”¨ __u32 和类似 的类型。 å¯èƒ½è¿˜æœ‰å…¶ä»–的情况,ä¸è¿‡åŸºæœ¬çš„规则是 **永远ä¸è¦** 使用 typedef,除éžä½ å¯ä»¥æ˜Ž 确的应用上述æŸä¸ªè§„则ä¸çš„一个。 总的æ¥è¯´ï¼Œå¦‚æžœä¸€ä¸ªæŒ‡é’ˆæˆ–è€…ä¸€ä¸ªç»“æž„ä½“é‡Œçš„å…ƒç´ å¯ä»¥åˆç†çš„被直接访问到,那么它们 å°±ä¸åº”该是一个 typedef。 6) 函数 ------- 函数应该简çŸè€Œæ¼‚亮,并且åªå®Œæˆä¸€ä»¶äº‹æƒ…。函数应该å¯ä»¥ä¸€å±æˆ–者两å±æ˜¾ç¤ºå®Œ (我们 éƒ½çŸ¥é“ ISO/ANSI å±å¹•å¤§å°æ˜¯ 80x24),åªåšä¸€ä»¶äº‹æƒ…,而且把它åšå¥½ã€‚ 一个函数的最大长度是和该函数的å¤æ‚度和缩进级数æˆåæ¯”çš„ã€‚æ‰€ä»¥ï¼Œå¦‚æžœä½ æœ‰ä¸€ä¸ªç† è®ºä¸Šå¾ˆç®€å•çš„åªæœ‰ä¸€ä¸ªå¾ˆé•¿ (但是简å•) çš„ case è¯å¥çš„å‡½æ•°ï¼Œè€Œä¸”ä½ éœ€è¦åœ¨æ¯ä¸ª case 里åšå¾ˆå¤šå¾ˆå°çš„äº‹æƒ…ï¼Œè¿™æ ·çš„å‡½æ•°å°½ç®¡å¾ˆé•¿ï¼Œä½†ä¹Ÿæ˜¯å¯ä»¥çš„。 ä¸è¿‡ï¼Œå¦‚æžœä½ æœ‰ä¸€ä¸ªå¤æ‚çš„å‡½æ•°ï¼Œè€Œä¸”ä½ æ€€ç–‘ä¸€ä¸ªå¤©åˆ†ä¸æ˜¯å¾ˆé«˜çš„高ä¸ä¸€å¹´çº§å¦ç”Ÿå¯èƒ½ 甚至æžä¸æ¸…æ¥šè¿™ä¸ªå‡½æ•°çš„ç›®çš„ï¼Œä½ åº”è¯¥ä¸¥æ ¼éµå®ˆå‰é¢æ到的长度é™åˆ¶ã€‚使用辅助函数, 并为之å–个具æ述性的åå— (å¦‚æžœä½ è§‰å¾—å®ƒä»¬çš„æ€§èƒ½å¾ˆé‡è¦çš„è¯ï¼Œå¯ä»¥è®©ç¼–译器内è”它 ä»¬ï¼Œè¿™æ ·çš„æ•ˆæžœå¾€å¾€ä¼šæ¯”ä½ å†™ä¸€ä¸ªå¤æ‚函数的效果è¦å¥½ã€‚) 函数的å¦å¤–一个衡é‡æ ‡å‡†æ˜¯æœ¬åœ°å˜é‡çš„æ•°é‡ã€‚æ¤æ•°é‡ä¸åº”超过 5ï¼10 个,å¦åˆ™ä½ 的函数 就有问题了。é‡æ–°è€ƒè™‘ä¸€ä¸‹ä½ çš„å‡½æ•°ï¼ŒæŠŠå®ƒåˆ†æ‹†æˆæ›´å°çš„函数。人的大脑一般å¯ä»¥è½»æ¾ çš„åŒæ—¶è·Ÿè¸ª 7 个ä¸åŒçš„事物,如果å†å¢žå¤šçš„è¯ï¼Œå°±ä¼šç³Šæ¶‚了。å³ä¾¿ä½ èªé¢–è¿‡äººï¼Œä½ ä¹Ÿå¯ èƒ½ä¼šè®°ä¸æ¸…ä½ 2 个星期å‰åšè¿‡çš„事情。 在æºæ–‡ä»¶é‡Œï¼Œä½¿ç”¨ç©ºè¡Œéš”å¼€ä¸åŒçš„函数。如果该函数需è¦è¢«å¯¼å‡ºï¼Œå®ƒçš„ **EXPORT** å® åº”è¯¥ç´§è´´åœ¨å®ƒçš„ç»“æŸå¤§æ‹¬å·ä¹‹ä¸‹ã€‚比如: .. code-block:: c int system_is_up(void) { return system_state == SYSTEM_RUNNING; } EXPORT_SYMBOL(system_is_up); 6.1) 函数原型 ************* 在函数原型ä¸åŒ…å«å‚æ•°å和它们的数æ®ç±»åž‹ã€‚虽然 C è¯è¨€é‡Œæ²¡æœ‰è¿™æ ·çš„è¦æ±‚,但在 Linux 里这是æ倡的åšæ³•ï¼Œå› ä¸ºè¿™æ ·å¯ä»¥å¾ˆç®€å•çš„给读者æ供更多的有价值的信æ¯ã€‚ ä¸è¦åœ¨å‡½æ•°å£°æ˜Žé‡Œä½¿ç”¨ ``extern`` 关键å—ï¼Œå› ä¸ºè¿™ä¼šå¯¼è‡´ä»£ç è¡Œå˜é•¿ï¼Œå¹¶ä¸”ä¸æ˜¯ä¸¥æ ¼ 必需的。 写函数原型时,请ä¿æŒ `å…ƒç´ é¡ºåºè§„则 <https://lore.kernel.org/mm-commits/CAHk-=wiOCLRny5aifWNhr621kYrJwhfURsa0vFPeUEm8mF0ufg@mail.gmail.com/>`_ 。 例如下列函数声明:: __init void * __must_check action(enum magic value, size_t size, u8 count, char *fmt, ...) __printf(4, 5) __malloc; 推èçš„å‡½æ•°åŽŸåž‹å…ƒç´ é¡ºåºæ˜¯ï¼š - 储å˜ç±»åž‹ï¼ˆä¸‹æ–¹çš„ ``static __always_inline`` ï¼Œæ³¨æ„ ``__always_inline`` 技术上æ¥è®²æ˜¯ä¸ªå±žæ€§ä½†è¢«å½“åš ``inline`` ) - 储å˜ç±»åž‹å±žæ€§ï¼ˆä¸Šæ–¹çš„ ``__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 è¯å¥å°±å¾ˆæ–¹ 便了。如果并ä¸éœ€è¦æ¸…ç†æ“作,那么直接 return å³å¯ã€‚ 选择一个能够说明 goto 行为或它为何å˜åœ¨çš„æ ‡ç¾å。如果 goto è¦é‡Šæ”¾ ``buffer``, 一个ä¸é”™çš„åå—å¯ä»¥æ˜¯ ``out_free_buffer:`` ã€‚åˆ«åŽ»ä½¿ç”¨åƒ ``err1:`` å’Œ ``err2:`` è¿™æ ·çš„GW_BASIC åç§°ï¼Œå› ä¸ºä¸€æ—¦ä½ æ·»åŠ æˆ–åˆ é™¤äº† (函数的) é€€å‡ºè·¯å¾„ï¼Œä½ å°±å¿…é¡»å¯¹å®ƒä»¬ é‡æ–°ç¼–å·ï¼Œè¿™æ ·ä¼šéš¾ä»¥åŽ»æ£€éªŒæ£ç¡®æ€§ã€‚ 使用 goto çš„ç†ç”±æ˜¯ï¼š - æ— æ¡ä»¶è¯å¥å®¹æ˜“ç†è§£å’Œè·Ÿè¸ª - 嵌套程度å‡å° - å¯ä»¥é¿å…由于修改时忘记更新个别的退出点而导致错误 - 让编译器çœåŽ»åˆ 除冗余代ç 的工作 ;) .. code-block:: c 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; } 一个需è¦æ³¨æ„的常è§é”™è¯¯æ˜¯ ``å• err 错误`` ,就åƒè¿™æ ·ï¼š .. code-block:: c err: kfree(foo->bar); kfree(foo); return ret; 这段代ç 的错误是,在æŸäº›é€€å‡ºè·¯å¾„上 ``foo`` 是 NULL。通常情况下,通过把它分离 æˆä¸¤ä¸ªé”™è¯¯æ ‡ç¾ ``err_free_bar:`` å’Œ ``err_free_foo:`` æ¥ä¿®å¤è¿™ä¸ªé”™è¯¯ï¼š .. code-block:: c err_free_bar: kfree(foo->bar); err_free_foo: kfree(foo); return ret; ç†æƒ³æƒ…å†µä¸‹ï¼Œä½ åº”è¯¥æ¨¡æ‹Ÿé”™è¯¯æ¥æµ‹è¯•æ‰€æœ‰é€€å‡ºè·¯å¾„。 8) 注释 ------- 注释是好的,ä¸è¿‡æœ‰è¿‡åº¦æ³¨é‡Šçš„å±é™©ã€‚永远ä¸è¦åœ¨æ³¨é‡Šé‡Œè§£é‡Šä½ 的代ç 是如何è¿ä½œçš„: 更好的åšæ³•æ˜¯è®©åˆ«äººä¸€çœ‹ä½ 的代ç å°±å¯ä»¥æ˜Žç™½ï¼Œè§£é‡Šå†™çš„很差的代ç 是浪费时间。 一般æ¥è¯´ä½ ç”¨æ³¨é‡Šå‘Šè¯‰åˆ«äººä½ çš„ä»£ç åšäº†ä»€ä¹ˆï¼Œè€Œä¸æ˜¯æ€Žä¹ˆåšçš„ã€‚ä¹Ÿè¯·ä½ ä¸è¦æŠŠ 注释放在一个函数体内部:如果函数å¤æ‚åˆ°ä½ éœ€è¦ç‹¬ç«‹çš„注释其ä¸çš„ä¸€éƒ¨åˆ†ï¼Œä½ å¾ˆå¯èƒ½ 需è¦å›žåˆ°ç¬¬å…ç« çœ‹ä¸€çœ‹ã€‚ä½ å¯ä»¥åšä¸€äº›å°æ³¨é‡Šæ¥æ³¨æ˜Žæˆ–è¦å‘ŠæŸäº›å¾ˆèªæ˜Ž (或者槽糕) çš„ åšæ³•ï¼Œä½†ä¸è¦åŠ å¤ªå¤šã€‚ä½ åº”è¯¥åšçš„,是把注释放在函数的头部,告诉人们它åšäº†ä»€ä¹ˆï¼Œ 也å¯ä»¥åŠ 上它åšè¿™äº›äº‹æƒ…çš„åŽŸå› ã€‚ å½“æ³¨é‡Šå†…æ ¸ API 函数时,请使用 kernel-doc æ ¼å¼ã€‚è¯¦è§ Documentation/translations/zh_CN/doc-guide/index.rst å’Œ scripts/kernel-doc 。 é•¿ (多行) æ³¨é‡Šçš„é¦–é€‰é£Žæ ¼æ˜¯ï¼š .. code-block:: c /* * 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. */ 注释数æ®ä¹Ÿæ˜¯å¾ˆé‡è¦çš„,ä¸ç®¡æ˜¯åŸºæœ¬ç±»åž‹è¿˜æ˜¯è¡ç”Ÿç±»åž‹ã€‚为了方便实现这一点,æ¯ä¸€è¡Œ 应åªå£°æ˜Žä¸€ä¸ªæ•°æ® (ä¸è¦ä½¿ç”¨é€—å·æ¥ä¸€æ¬¡å£°æ˜Žå¤šä¸ªæ•°æ®)ã€‚è¿™æ ·ä½ å°±æœ‰ç©ºé—´æ¥ä¸ºæ¯ä¸ªæ•°æ® 写一段å°æ³¨é‡Šæ¥è§£é‡Šå®ƒä»¬çš„用途了。 9) ä½ å·²ç»æŠŠäº‹æƒ…弄糟了 --------------------- è¿™æ²¡ä»€ä¹ˆï¼Œæˆ‘ä»¬éƒ½æ˜¯è¿™æ ·ã€‚å¯èƒ½ä½ 长期使用 Unix 的朋å‹å·²ç»å‘Šè¯‰ä½ ``GNU emacs`` èƒ½è‡ªåŠ¨å¸®ä½ æ ¼å¼åŒ– C æºä»£ç ï¼Œè€Œä¸”ä½ ä¹Ÿæ³¨æ„åˆ°äº†ï¼Œç¡®å®žæ˜¯è¿™æ ·ï¼Œä¸è¿‡å®ƒ 所使用的默认值和我们想è¦çš„相去甚远 (实际上,甚至比éšæœºæ‰“的还è¦å·®â€”â€”æ— æ•°ä¸ªçŒ´å 在 GNU emacs 里打å—永远ä¸ä¼šåˆ›é€ 出一个好程åº) *(译注:Infinite Monkey Theorem)* æ‰€ä»¥ä½ è¦ä¹ˆæ”¾å¼ƒ GNU emacs,è¦ä¹ˆæ”¹å˜å®ƒè®©å®ƒä½¿ç”¨æ›´åˆç†çš„设定。è¦é‡‡ç”¨åŽä¸€ä¸ªæ–¹æ¡ˆï¼Œ ä½ å¯ä»¥æŠŠä¸‹é¢è¿™æ®µç²˜è´´åˆ°ä½ çš„ .emacs 文件里。 .. code-block:: elisp (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 在 ``~/src/linux-trees`` 下的 C æºæ–‡ä»¶èŽ·å¾—æ›´å¥½çš„å†…æ ¸ä»£ç é£Žæ ¼ã€‚ ä¸è¿‡å°±ç®—ä½ å°è¯•è®© emacs æ£ç¡®çš„æ ¼å¼åŒ–代ç 失败了,也并ä¸æ„味ç€ä½ å¤±åŽ»äº†ä¸€åˆ‡ï¼šè¿˜å¯ ä»¥ç”¨ ``indent`` 。 ä¸è¿‡ï¼ŒGNU indent 也有和 GNU emacs ä¸€æ ·æœ‰é—®é¢˜çš„è®¾å®šï¼Œæ‰€ä»¥ä½ éœ€è¦ç»™å®ƒä¸€äº›å‘½ä»¤é€‰ 项。ä¸è¿‡ï¼Œè¿™è¿˜ä¸ç®—å¤ªç³Ÿç³•ï¼Œå› ä¸ºå°±ç®—æ˜¯ GNU indent çš„ä½œè€…ä¹Ÿè®¤åŒ K&R çš„æƒå¨æ€§ (GNU 的人并ä¸æ˜¯å人,他们åªæ˜¯åœ¨è¿™ä¸ªé—®é¢˜ä¸Šè¢«ä¸¥é‡çš„误导了)ï¼Œæ‰€ä»¥ä½ åªè¦ç»™ indent 指定选项 ``-kr -i8`` (代表 ``K&R,8 å—符缩进``),或使用 ``scripts/Lindent`` è¿™æ ·å°±å¯ä»¥ä»¥æœ€æ—¶é«¦çš„æ–¹å¼ç¼©è¿›æºä»£ç 。 ``indent`` 有很多选项,特别是é‡æ–°æ ¼å¼åŒ–æ³¨é‡Šçš„æ—¶å€™ï¼Œä½ å¯èƒ½éœ€è¦çœ‹ä¸€ä¸‹å®ƒçš„手册。 ä¸è¿‡è®°ä½ï¼š ``indent`` ä¸èƒ½ä¿®æ£åçš„ç¼–ç¨‹ä¹ æƒ¯ã€‚ 请注æ„,您还å¯ä»¥ä½¿ç”¨ ``clang-format`` 工具帮助您处ç†è¿™äº›è§„则,快速自动é‡æ–°æ ¼ å¼åŒ–部分代ç ,并审阅整个文件以å‘现代ç é£Žæ ¼é”™è¯¯ã€æ‰“å—错误和å¯èƒ½çš„æ”¹è¿›ã€‚å®ƒè¿˜å¯ ä»¥æ–¹ä¾¿åœ°æŽ’åº ``#include`` ,对é½å˜é‡/å®ï¼Œé‡æŽ’文本和其他类似任务。 è¯¦è§ Documentation/dev-tools/clang-format.rst 。 10) Kconfig é…置文件 -------------------- 对于é布æºç æ ‘çš„æ‰€æœ‰ Kconfig* é…置文件æ¥è¯´ï¼Œå®ƒä»¬ç¼©è¿›æ–¹å¼æœ‰æ‰€ä¸åŒã€‚ç´§æŒ¨ç€ ``config`` 定义的行,用一个制表符缩进,然而 help ä¿¡æ¯çš„缩进则é¢å¤–å¢žåŠ 2 个空 æ ¼ã€‚ä¸¾ä¸ªä¾‹å:: 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 ... è¦æŸ¥çœ‹é…置文件的完整文档,请看 Documentation/kbuild/kconfig-language.rst 。 11) æ•°æ®ç»“æž„ ------------ 如果一个数æ®ç»“构,在创建和销æ¯å®ƒçš„å•çº¿æ‰§è¡ŒçŽ¯å¢ƒä¹‹å¤–å¯è§ï¼Œé‚£ä¹ˆå®ƒå¿…é¡»è¦æœ‰ä¸€ä¸ªå¼• ç”¨è®¡æ•°å™¨ã€‚å†…æ ¸é‡Œæ²¡æœ‰åžƒåœ¾æ”¶é›† (å¹¶ä¸”å†…æ ¸ä¹‹å¤–çš„åžƒåœ¾æ”¶é›†æ…¢ä¸”æ•ˆçŽ‡ä½Žä¸‹),这æ„味ç€ä½ ç»å¯¹éœ€è¦è®°å½•ä½ 对这ç§æ•°æ®ç»“构的使用情况。 引用计数æ„味ç€ä½ 能够é¿å…上é”,并且å…许多个用户并行访问这个数æ®ç»“构——而ä¸éœ€è¦ 担心这个数æ®ç»“æž„ä»…ä»…å› ä¸ºæš‚æ—¶ä¸è¢«ä½¿ç”¨å°±æ¶ˆå¤±äº†ï¼Œé‚£äº›ç”¨æˆ·å¯èƒ½ä¸è¿‡æ˜¯æ²‰ç¡äº†ä¸€é˜µæˆ– 者åšäº†ä¸€äº›å…¶ä»–事情而已。 注æ„ä¸Šé” **ä¸èƒ½** å–代引用计数。上é”是为了ä¿æŒæ•°æ®ç»“构的一致性,而引用计数是一 个内å˜ç®¡ç†æŠ€å·§ã€‚通常二者都需è¦ï¼Œä¸è¦æŠŠä¸¤ä¸ªæžæ··äº†ã€‚ 很多数æ®ç»“构实际上有 2 级引用计数,它们通常有ä¸åŒ ``ç±»`` 的用户。å类计数器统 计å类用户的数é‡ï¼Œæ¯å½“å类计数器å‡è‡³é›¶æ—¶ï¼Œå…¨å±€è®¡æ•°å™¨å‡ä¸€ã€‚ è¿™ç§ ``多级引用计数`` 的例åå¯ä»¥åœ¨å†…å˜ç®¡ç† (``struct mm_struct``: mm_users å’Œ mm_count),和文件系统 (``struct super_block``: s_count å’Œ s_active) ä¸æ‰¾åˆ°ã€‚ è®°ä½ï¼šå¦‚æžœå¦ä¸€ä¸ªæ‰§è¡Œçº¿ç´¢å¯ä»¥æ‰¾åˆ°ä½ çš„æ•°æ®ç»“构,但这个数æ®ç»“构没有引用计数器, è¿™é‡Œå‡ ä¹Žè‚¯å®šæ˜¯ä¸€ä¸ª bug。 12) å®ï¼Œæžšä¸¾å’ŒRTL ----------------- 用于定义常é‡çš„å®çš„åå—åŠæžšä¸¾é‡Œçš„æ ‡ç¾éœ€è¦å¤§å†™ã€‚ .. code-block:: c #define CONSTANT 0x12345 åœ¨å®šä¹‰å‡ ä¸ªç›¸å…³çš„å¸¸é‡æ—¶ï¼Œæœ€å¥½ç”¨æžšä¸¾ã€‚ å®çš„åå—请用大写å—æ¯ï¼Œä¸è¿‡å½¢å¦‚函数的å®çš„åå—å¯ä»¥ç”¨å°å†™å—æ¯ã€‚ 通常如果能写æˆå†…è”函数就ä¸è¦å†™æˆåƒå‡½æ•°çš„å®ã€‚ å«æœ‰å¤šä¸ªè¯å¥çš„å®åº”该被包å«åœ¨ä¸€ä¸ª do-while 代ç å—里: .. code-block:: c #define macrofun(a, b, c) \ do { \ if (a == 5) \ do_this(b, c); \ } while (0) 使用å®çš„时候应é¿å…的事情: 1) å½±å“控制æµç¨‹çš„å®ï¼š .. code-block:: c #define FOO(x) \ do { \ if (blah(x) < 0) \ return -EBUGGERED; \ } while (0) **éžå¸¸** ä¸å¥½ã€‚它看起æ¥åƒä¸€ä¸ªå‡½æ•°ï¼Œä¸è¿‡å´èƒ½å¯¼è‡´ ``调用`` 它的函数退出;ä¸è¦æ‰“ 乱读者大脑里的è¯æ³•åˆ†æžå™¨ã€‚ 2) ä¾èµ–于一个固定åå—的本地å˜é‡çš„å®ï¼š .. code-block:: c #define FOO(val) bar(index, val) å¯èƒ½çœ‹èµ·æ¥åƒæ˜¯ä¸ªä¸é”™çš„东西,ä¸è¿‡å®ƒéžå¸¸å®¹æ˜“把读代ç 的人æžç³Šæ¶‚,而且容易导致看起 æ¥ä¸ç›¸å…³çš„改动带æ¥é”™è¯¯ã€‚ 3) 作为左值的带å‚æ•°çš„å®ï¼š FOO(x) = y;如果有人把 FOO å˜æˆä¸€ä¸ªå†…è”函数的è¯ï¼Œè¿™ ç§ç”¨æ³•å°±ä¼šå‡ºé”™äº†ã€‚ 4) 忘记了优先级:使用表达å¼å®šä¹‰å¸¸é‡çš„å®å¿…须将表达å¼ç½®äºŽä¸€å¯¹å°æ‹¬å·ä¹‹å†…。带å‚æ•° çš„å®ä¹Ÿè¦æ³¨æ„æ¤ç±»é—®é¢˜ã€‚ .. code-block:: c #define CONSTANT 0x4000 #define CONSTEXP (CONSTANT | 3) 5) 在å®é‡Œå®šä¹‰ç±»ä¼¼å‡½æ•°çš„本地å˜é‡æ—¶å‘½å冲çªï¼š .. code-block:: c #define FOO(x) \ ({ \ typeof(x) ret; \ ret = calc_ret(x); \ (ret); \ }) ret 是本地å˜é‡çš„通用åå——— __foo_ret æ›´ä¸å®¹æ˜“与一个已å˜åœ¨çš„å˜é‡å†²çªã€‚ cpp 手册对å®çš„讲解很详细。gcc internals 手册也详细讲解了 RTLï¼Œå†…æ ¸é‡Œçš„æ±‡ç¼–è¯ è¨€ç»å¸¸ç”¨åˆ°å®ƒã€‚ 13) 打å°å†…æ ¸æ¶ˆæ¯ ---------------- å†…æ ¸å¼€å‘者应该看起æ¥æœ‰æ–‡åŒ–。请一定注æ„å†…æ ¸ä¿¡æ¯çš„拼写,以给人良好的å°è±¡ã€‚ ä¸è¦ç”¨ä¸è§„范的å•è¯æ¯”如 ``dont``,而è¦ç”¨ ``do not`` 或者 ``don't`` 。ä¿è¯è¿™äº›ä¿¡ æ¯ç®€å•æ˜Žäº†ã€æ— æ§ä¹‰ã€‚ å†…æ ¸ä¿¡æ¯ä¸å¿…以英文å¥å·ç»“æŸã€‚ 在å°æ‹¬å·é‡Œæ‰“å°æ•°å— (%d) 没有任何价值,应该é¿å…è¿™æ ·åšã€‚ <linux/device.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(),一个相关约定是在一 个已ç»å¼€å¯äº† DEBUG 时,使用 VERBOSE_DEBUG æ¥æ·»åŠ dev_vdbg()。 许多å系统拥有 Kconfig 调试选项æ¥å¼€å¯å¯¹åº” Makefile 里é¢çš„ -DDEBUG;在其他 情况下,特殊文件使用 #define DEBUG。当一æ¡è°ƒè¯•ä¿¡æ¯éœ€è¦è¢«æ— æ¡ä»¶æ‰“å°æ—¶ï¼Œä¾‹å¦‚, 如果已ç»åŒ…å«ä¸€ä¸ªè°ƒè¯•ç›¸å…³çš„ #ifdef æ¡ä»¶ï¼Œprintk(KERN_DEBUG ...) å°±å¯è¢«ä½¿ç”¨ã€‚ 14) 分é…å†…å˜ ------------ å†…æ ¸æ供了下é¢çš„一般用途的内å˜åˆ†é…函数: kmalloc(), kzalloc(), kmalloc_array(), kcalloc(), vmalloc() å’Œ vzalloc()。 请å‚考 API 文档以获å–有关它们的详细信æ¯ï¼š Documentation/translations/zh_CN/core-api/memory-allocation.rst 。 ä¼ é€’ç»“æž„ä½“å¤§å°çš„首选形å¼æ˜¯è¿™æ ·çš„: .. code-block:: c p = kmalloc(sizeof(*p), ...); å¦å¤–一ç§ä¼ 递方å¼ä¸ï¼Œsizeof çš„æ“作数是结构体的åå—ï¼Œè¿™æ ·ä¼šé™ä½Žå¯è¯»æ€§ï¼Œå¹¶ä¸”å¯èƒ½ 会引入 bug。有å¯èƒ½æŒ‡é’ˆå˜é‡ç±»åž‹è¢«æ”¹å˜æ—¶ï¼Œè€Œå¯¹åº”çš„ä¼ é€’ç»™å†…å˜åˆ†é…函数的 sizeof 的结果ä¸å˜ã€‚ 强制转æ¢ä¸€ä¸ª void 指针返回值是多余的。C è¯è¨€æœ¬èº«ä¿è¯äº†ä»Ž void 指针到其他任何 指针类型的转æ¢æ˜¯æ²¡æœ‰é—®é¢˜çš„。 分é…一个数组的首选形å¼æ˜¯è¿™æ ·çš„: .. code-block:: c p = kmalloc_array(n, sizeof(...), ...); 分é…一个零长数组的首选形å¼æ˜¯è¿™æ ·çš„: .. code-block:: c p = kcalloc(n, sizeof(...), ...); 两ç§å½¢å¼éƒ½ä¼šæ£€æŸ¥åˆ†é… n * sizeof(...) 大å°æ—¶å†…å˜çš„溢出,如果溢出返回 NULL。 在没有 __GFP_NOWARN 的情况下使用时,这些通用分é…函数都会在失败时å‘èµ·å †æ ˆè½¬å‚¨ï¼Œ å› æ¤å½“返回NULL时,没有必è¦å‘出é¢å¤–的失败消æ¯ã€‚ 15) 内è”弊病 ------------ 有一个常è§çš„误解是 ``内è”`` 是 gcc æ供的å¯ä»¥è®©ä»£ç è¿è¡Œæ›´å¿«çš„一个选项。虽然使 用内è”函数有时候是æ°å½“çš„ (比如作为一ç§æ›¿ä»£å®çš„æ–¹å¼ï¼Œè¯·çœ‹ç¬¬åäºŒç« ),ä¸è¿‡å¾ˆå¤šæƒ… 况下ä¸æ˜¯è¿™æ ·ã€‚inline çš„è¿‡åº¦ä½¿ç”¨ä¼šä½¿å†…æ ¸å˜å¤§ï¼Œä»Žè€Œä½¿æ•´ä¸ªç³»ç»Ÿè¿è¡Œé€Ÿåº¦å˜æ…¢ã€‚ å› ä¸ºä½“ç§¯å¤§å†…æ ¸ä¼šå 用更多的指令高速缓å˜ï¼Œè€Œä¸”会导致 pagecache çš„å¯ç”¨å†…å˜å‡å°‘。 想象一下,一次 pagecache 未命ä¸å°±ä¼šå¯¼è‡´ä¸€æ¬¡ç£ç›˜å¯»å€ï¼Œå°†è€—æ—¶ 5 毫秒。5 毫秒的 时间内 CPU 能执行很多很多指令。 一个基本的原则是如果一个函数有 3 行以上,就ä¸è¦æŠŠå®ƒå˜æˆå†…è”函数。这个原则的一 ä¸ªä¾‹å¤–æ˜¯ï¼Œå¦‚æžœä½ çŸ¥é“æŸä¸ªå‚数是一个编译时常é‡ï¼Œè€Œä¸”å› ä¸ºè¿™ä¸ªå¸¸é‡ä½ 确定编译器在 ç¼–è¯‘æ—¶èƒ½ä¼˜åŒ–æŽ‰ä½ çš„å‡½æ•°çš„å¤§éƒ¨åˆ†ä»£ç ,那ä»ç„¶å¯ä»¥ç»™å®ƒåŠ 上 inline 关键å—。 kmalloc() 内è”函数就是一个很好的例å。 人们ç»å¸¸ä¸»å¼ ç»™ static 的而且åªç”¨äº†ä¸€æ¬¡çš„å‡½æ•°åŠ ä¸Š inline,如æ¤ä¸ä¼šæœ‰ä»»ä½•æŸå¤±ï¼Œ å› ä¸ºæ²¡æœ‰ä»€ä¹ˆå¥½æƒè¡¡çš„。虽然从技术上说这是æ£ç¡®çš„,但是实际上这ç§æƒ…况下å³ä½¿ä¸åŠ inline gcc 也å¯ä»¥è‡ªåŠ¨ä½¿å…¶å†…è”。而且其他用户å¯èƒ½ä¼šè¦æ±‚移除 inline,由æ¤è€Œæ¥çš„ 争论会抵消 inline 自身的潜在价值,得ä¸å¿å¤±ã€‚ 16) 函数返回值åŠå‘½å -------------------- 函数å¯ä»¥è¿”回多ç§ä¸åŒç±»åž‹çš„值,最常è§çš„一ç§æ˜¯è¡¨æ˜Žå‡½æ•°æ‰§è¡ŒæˆåŠŸæˆ–è€…å¤±è´¥çš„å€¼ã€‚è¿™æ · 的一个值å¯ä»¥è¡¨ç¤ºä¸ºä¸€ä¸ªé”™è¯¯ä»£ç æ•´æ•° (-Exxxï¼å¤±è´¥ï¼Œ0ï¼æˆåŠŸ) 或者一个 ``æˆåŠŸ`` 布尔值 (0ï¼å¤±è´¥ï¼Œéž0ï¼æˆåŠŸ)。 æ··åˆä½¿ç”¨è¿™ä¸¤ç§è¡¨è¾¾æ–¹å¼æ˜¯éš¾äºŽå‘现的 bug çš„æ¥æºã€‚如果 C è¯è¨€æœ¬èº«ä¸¥æ ¼åŒºåˆ†æ•´å½¢å’Œ 布尔型å˜é‡ï¼Œé‚£ä¹ˆç¼–译器就能够帮我们å‘现这些错误... ä¸è¿‡ C è¯è¨€ä¸åŒºåˆ†ã€‚为了é¿å… äº§ç”Ÿè¿™ç§ bug,请éµå¾ªä¸‹é¢çš„惯例:: 如果函数的åå—是一个动作或者强制性的命令,那么这个函数应该返回错误代 ç 整数。如果是一个判æ–,那么函数应该返回一个“æˆåŠŸâ€å¸ƒå°”值。 比如, ``add work`` 是一个命令,所以 add_work() 在æˆåŠŸæ—¶è¿”回 0,在失败时返回 -EBUSYã€‚ç±»ä¼¼çš„ï¼Œå› ä¸º ``PCI device present`` 是一个判æ–,所以 pci_dev_present() 在æˆåŠŸæ‰¾åˆ°ä¸€ä¸ªåŒ¹é…的设备时应该返回 1,如果找ä¸åˆ°æ—¶åº”该返回 0。 所有 EXPORTed 函数都必须éµå®ˆè¿™ä¸ªæƒ¯ä¾‹ï¼Œæ‰€æœ‰çš„公共函数也都应该如æ¤ã€‚ç§æœ‰ (static) 函数ä¸éœ€è¦å¦‚æ¤ï¼Œä½†æ˜¯æˆ‘们也推èè¿™æ ·åšã€‚ 返回值是实际计算结果而ä¸æ˜¯è®¡ç®—是å¦æˆåŠŸçš„æ ‡å¿—çš„å‡½æ•°ä¸å—æ¤æƒ¯ä¾‹çš„é™åˆ¶ã€‚通常 他们通过返回一些æ£å¸¸å€¼èŒƒå›´ä¹‹å¤–的结果æ¥è¡¨ç¤ºå‡ºé”™ã€‚典型的例å是返回指针的函数, 他们使用 NULL 或者 ERR_PTR 机制æ¥æŠ¥å‘Šé”™è¯¯ã€‚ 17) 使用布尔类型 ---------------- Linuxå†…æ ¸å¸ƒå°”ï¼ˆbool)类型是C99 _Bool类型的别å。布尔值åªèƒ½ä¸º0或1,而对布尔的 éšå¼æˆ–显å¼è½¬æ¢å°†è‡ªåŠ¨å°†å€¼è½¬æ¢ä¸ºtrue或false。在使用布尔类型时 **ä¸éœ€è¦** æž„é€ ï¼Œ 它会消除一类错误。 使用布尔值时,应使用trueå’Œfalse定义,而ä¸æ˜¯1å’Œ0。 å¸ƒå°”å‡½æ•°è¿”å›žç±»åž‹å’Œå †æ ˆå˜é‡æ€»æ˜¯å¯ä»¥åœ¨é€‚当的时候使用。鼓励使用布尔æ¥æ高å¯è¯»æ€§ï¼Œ 并且布尔值在å˜å‚¨æ—¶é€šå¸¸æ¯”“intâ€æ›´å¥½ã€‚ 如果缓å˜è¡Œå¸ƒå±€æˆ–值的大å°å¾ˆé‡è¦ï¼Œè¯·ä¸è¦ä½¿ç”¨å¸ƒå°”ï¼Œå› ä¸ºå…¶å¤§å°å’Œå¯¹é½æ–¹å¼æ ¹æ®ç¼–译 的体系结构而ä¸åŒã€‚针对对é½å’Œå¤§å°è¿›è¡Œä¼˜åŒ–的结构体ä¸åº”使用布尔。 如果一个结构体有多个true/false值,请考虑将它们åˆå¹¶ä¸ºå…·æœ‰1比特æˆå‘˜çš„ä½åŸŸï¼Œæˆ–使 用适当的固定宽度类型,如u8。 类似地,对于函数å‚数,多个true/false值å¯ä»¥åˆå¹¶ä¸ºå•ä¸ªæŒ‰ä½çš„â€œæ ‡å¿—â€å‚数,如果调 用点具有裸true/false常é‡ï¼Œâ€œæ ‡å¿—â€å‚数通常是更具å¯è¯»æ€§çš„替代方法。 总之,在结构体和å‚æ•°ä¸æœ‰é™åœ°ä½¿ç”¨å¸ƒå°”å¯ä»¥æ高å¯è¯»æ€§ã€‚ 18) ä¸è¦é‡æ–°å‘æ˜Žå†…æ ¸å® ---------------------- 头文件 include/linux/kernel.h 包å«äº†ä¸€äº›å®ï¼Œä½ 应该使用它们,而ä¸è¦è‡ªå·±å†™ä¸€äº› 它们的å˜ç§ã€‚æ¯”å¦‚ï¼Œå¦‚æžœä½ éœ€è¦è®¡ç®—ä¸€ä¸ªæ•°ç»„çš„é•¿åº¦ï¼Œä½¿ç”¨è¿™ä¸ªå® .. code-block:: c #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) ç±»ä¼¼çš„ï¼Œå¦‚æžœä½ è¦è®¡ç®—æŸç»“构体æˆå‘˜çš„大å°ï¼Œä½¿ç”¨ .. code-block:: c #define sizeof_field(t, f) (sizeof(((t*)0)->f)) 还有å¯ä»¥åšä¸¥æ ¼çš„类型检查的 min() å’Œ max() å®ï¼Œå¦‚æžœä½ éœ€è¦å¯ä»¥ä½¿ç”¨å®ƒä»¬ã€‚ä½ å¯ä»¥ è‡ªå·±çœ‹çœ‹é‚£ä¸ªå¤´æ–‡ä»¶é‡Œè¿˜å®šä¹‰äº†ä»€ä¹ˆä½ å¯ä»¥æ‹¿æ¥ç”¨çš„东西,如果有定义的è¯ï¼Œä½ å°±ä¸åº” åœ¨ä½ çš„ä»£ç 里自己é‡æ–°å®šä¹‰ã€‚ 19) 编辑器模å¼è¡Œå’Œå…¶ä»–需è¦ç½—嗦的事情 ------------------------------------ 有一些编辑器å¯ä»¥è§£é‡ŠåµŒå…¥åœ¨æºæ–‡ä»¶é‡Œçš„ç”±ä¸€äº›ç‰¹æ®Šæ ‡è®°æ ‡æ˜Žçš„é…置信æ¯ã€‚比如,emacs 能够解æžè¢«æ ‡è®°æˆè¿™æ ·çš„行: .. code-block:: c -*- mode: c -*- æˆ–è€…è¿™æ ·çš„ï¼š .. code-block:: c /* Local Variables: compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c" End: */ Vim 能够解æžè¿™æ ·çš„æ ‡è®°ï¼š .. code-block:: c /* vim:set sw=8 noet */ ä¸è¦åœ¨æºä»£ç ä¸åŒ…å«ä»»ä½•è¿™æ ·çš„内容。æ¯ä¸ªäººéƒ½æœ‰ä»–自己的编辑器é…ç½®ï¼Œä½ çš„æºæ–‡ä»¶ä¸ 应该覆盖别人的é…置。这包括有关缩进和模å¼é…ç½®çš„æ ‡è®°ã€‚äººä»¬å¯ä»¥ä½¿ç”¨ä»–们自己定制 的模å¼ï¼Œæˆ–者使用其他å¯ä»¥äº§ç”Ÿæ£ç¡®çš„缩进的巧妙方法。 20) 内è”汇编 ------------ 在特定架构的代ç ä¸ï¼Œä½ å¯èƒ½éœ€è¦å†…è”汇编与 CPU 和平å°ç›¸å…³åŠŸèƒ½è¿žæŽ¥ã€‚需è¦è¿™ä¹ˆåšæ—¶ å°±ä¸è¦çŠ¹è±«ã€‚然而,当 C å¯ä»¥å®Œæˆå·¥ä½œæ—¶ï¼Œä¸è¦å¹³ç™½æ— 故地使用内è”汇编。在å¯èƒ½çš„情 å†µä¸‹ï¼Œä½ å¯ä»¥å¹¶ä¸”应该用 C 和硬件沟通。 请考虑去写æ†ç»‘通用ä½å…ƒ (wrap common bits) 的内è”汇编的简å•è¾…助函数,别去é‡å¤ 地写下åªæœ‰ç»†å¾®å·®å¼‚内è”汇编。记ä½å†…è”汇编å¯ä»¥ä½¿ç”¨ C å‚数。 大型,有一定å¤æ‚度的汇编函数应该放在 .S 文件内,用相应的 C 原型定义在 C 头文 件ä¸ã€‚汇编函数的 C 原型应该使用 ``asmlinkage`` 。 ä½ å¯èƒ½éœ€è¦æŠŠæ±‡ç¼–è¯å¥æ ‡è®°ä¸º volatile,用æ¥é˜»æ¢ GCC 在没å‘现任何副作用åŽå°±æŠŠå®ƒ ç§»é™¤äº†ã€‚ä½ ä¸å¿…æ€»æ˜¯è¿™æ ·åšï¼Œå°½ç®¡ï¼Œè¿™ä¸å¿…è¦çš„举动会é™åˆ¶ä¼˜åŒ–。 在写一个包å«å¤šæ¡æŒ‡ä»¤çš„å•ä¸ªå†…è”汇编è¯å¥æ—¶ï¼ŒæŠŠæ¯æ¡æŒ‡ä»¤ç”¨å¼•å·åˆ†å‰²è€Œä¸”å„å 一行, 除了最åŽä¸€æ¡æŒ‡ä»¤å¤–,在æ¯ä¸ªæŒ‡ä»¤ç»“å°¾åŠ ä¸Š ``\n\t`` ,让汇编输出时å¯ä»¥æ£ç¡®åœ°ç¼©è¿› 下一æ¡æŒ‡ä»¤ï¼š .. code-block:: c asm ("magic %reg1, #42\n\t" "more_magic %reg2, %reg3" : /* outputs */ : /* inputs */ : /* clobbers */); 21) æ¡ä»¶ç¼–译 ------------ åªè¦å¯èƒ½ï¼Œå°±ä¸è¦åœ¨ .c 文件里é¢ä½¿ç”¨é¢„处ç†æ¡ä»¶ (#if, #ifdef)ï¼›è¿™æ ·åšä¼šè®©ä»£ç æ›´éš¾ 阅读并且更难去跟踪逻辑。替代方案是,在头文件ä¸ç”¨é¢„处ç†æ¡ä»¶æ供给那些 .c 文件 使用,å†ç»™ #else æ供一个空桩 (no-op stub) 版本,然åŽåœ¨ .c æ–‡ä»¶å†…æ— æ¡ä»¶åœ°è°ƒç”¨ 那些 (定义在头文件内的) å‡½æ•°ã€‚è¿™æ ·åšï¼Œç¼–译器会é¿å…为桩函数 (stub) çš„è°ƒç”¨ç”Ÿæˆ ä»»ä½•ä»£ç ,产生的结果是相åŒçš„ï¼Œä½†é€»è¾‘å°†æ›´åŠ æ¸…æ™°ã€‚ 最好倾å‘于编译整个函数,而ä¸æ˜¯å‡½æ•°çš„一部分或表达å¼çš„一部分。与其放一个 ifdef 在表达å¼å†…,ä¸å¦‚分解出部分或全部表达å¼ï¼Œæ”¾è¿›ä¸€ä¸ªå•ç‹¬çš„è¾…åŠ©å‡½æ•°ï¼Œå¹¶åº”ç”¨é¢„å¤„ç† æ¡ä»¶åˆ°è¿™ä¸ªè¾…助函数内。 å¦‚æžœä½ æœ‰ä¸€ä¸ªåœ¨ç‰¹å®šé…ç½®ä¸ï¼Œå¯èƒ½å˜æˆæœªä½¿ç”¨çš„函数或å˜é‡ï¼Œç¼–译器会è¦å‘Šå®ƒå®šä¹‰äº†ä½† æœªä½¿ç”¨ï¼Œè¯·æŠŠå®ƒæ ‡è®°ä¸º __maybe_unused 而ä¸æ˜¯å°†å®ƒåŒ…å«åœ¨ä¸€ä¸ªé¢„处ç†æ¡ä»¶ä¸ã€‚(然而, 如果一个函数或å˜é‡æ€»æ˜¯æœªä½¿ç”¨ï¼Œå°±ç›´æŽ¥åˆ 除它。) 在代ç ä¸ï¼Œå°½å¯èƒ½åœ°ä½¿ç”¨ IS_ENABLED å®æ¥è½¬åŒ–æŸä¸ª Kconfig æ ‡è®°ä¸º C 的布尔 表达å¼ï¼Œå¹¶åœ¨ä¸€èˆ¬çš„ C æ¡ä»¶ä¸ä½¿ç”¨å®ƒï¼š .. code-block:: c if (IS_ENABLED(CONFIG_SOMETHING)) { ... } 编译器会åšå¸¸é‡æŠ˜å ,然åŽå°±åƒä½¿ç”¨ #ifdef é‚£æ ·åŽ»åŒ…å«æˆ–排除代ç å—,所以这ä¸ä¼šå¸¦ æ¥ä»»ä½•è¿è¡Œæ—¶å¼€é”€ã€‚然而,这ç§æ–¹æ³•ä¾æ—§å…许 C 编译器查看å—内的代ç ï¼Œå¹¶æ£€æŸ¥å®ƒçš„æ£ ç¡®æ€§ (è¯æ³•ï¼Œç±»åž‹ï¼Œç¬¦å·å¼•ç”¨ï¼Œç‰ç‰)ã€‚å› æ¤ï¼Œå¦‚æžœæ¡ä»¶ä¸æ»¡è¶³ï¼Œä»£ç å—内的引用符å·å°± ä¸å˜åœ¨æ—¶ï¼Œä½ 还是必须去用 #ifdef。 在任何有æ„义的 #if 或 #ifdef å—的末尾 (è¶…è¿‡å‡ è¡Œçš„),在 #endif åŒä¸€è¡Œçš„åŽé¢å†™ä¸‹ 注解,注释这个æ¡ä»¶è¡¨è¾¾å¼ã€‚例如: .. code-block:: c #ifdef CONFIG_SOMETHING ... #endif /* CONFIG_SOMETHING */ 附录 I) å‚考资料 ---------------- The C Programming Language, 2nd Edition 作者:Brian W. Kernighan å’Œ Denni M. Ritchie. Prentice Hall, Inc., 1988. ISBN 0-13-110362-8 (平装), 0-13-110370-9 (精装). .. note:: 《C程åºè®¾è®¡è¯è¨€ï¼ˆç¬¬2版)》 作者:[美] Brian W. Kernighan / [美] Dennis M. Ritchie 译者:å¾å®æ–‡ / æŽå¿— / å°¤æ™‹å…ƒï¼ˆå®¡æ ¡ï¼‰ 出版社:机械工业出版社,2019 ISBN:9787111617945 The Practice of Programming 作者:Brian W. Kernighan å’Œ Rob Pike. Addison-Wesley, Inc., 1999. ISBN 0-201-61586-X. .. note:: 《程åºè®¾è®¡å®žè·µã€‹ 作者:[美] Brian W. Kernighan / [美] Rob Pike 出版社:机械工业出版社,2005 ISBN:9787111091578 《程åºè®¾è®¡å®žè·µã€‹ 作者:[美] Brian W. Kernighan / Rob Pike 译者:裘宗燕 出版社:机械工业出版社,2000 ISBN:9787111075738 GNU 手册 - éµå¾ª K&R æ ‡å‡†å’Œæ¤æ–‡æœ¬ - cpp, gcc, gcc internals and indent, 都å¯ä»¥ä»Ž https://www.gnu.org/manual/ 找到 WG14 是 C è¯è¨€çš„å›½é™…æ ‡å‡†åŒ–å·¥ä½œç»„ï¼ŒURL: http://www.open-std.org/JTC1/SC22/WG14/ å†…æ ¸æ–‡æ¡£ Documentation/process/coding-style.rst, 作者 greg@kroah.com å‘表于 OLS 2002: http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/