0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

linux内核首选编码样式的文档

Q4MP_gh_c472c21 来源:未知 作者:李倩 2018-04-13 15:28 次阅读

每个人都有自己的编码风格,我不会将我的观点强加到任何人的身上,但这正是我所要保持的东西,就像其他许多事情一样。至少请考虑在这里所列出的观点。

首先,我建议打印出GNU编码标准的副本,不要去阅读,直接将它烧毁。这是一个伟大的象征性的姿态。

好,现在正式开始:

第1章:缩进

T一个Tab键有8个字符位因此一个缩进也是8个字符位. 有人试图将一个缩进定义场4个字符位甚至2个, 这无异于试图将Pi的值定义为3.

说明: 缩进的意义在于定义语句块的开始和结尾.尤其是当你紧盯屏幕20小时后你就更加能体会到缩进的作用了.

现在有些人说8字符长的缩进使得代码太靠右边,且很难在80字符的终端窗口阅读。事实是,如果你的代码需要三层以上的缩进,这是你犯糊涂了,你得修改你的程序。

总之,8字符缩进会让程序更好阅读,而而外的好处则是能够提醒你你的程序嵌套的太深了。这个需要警惕。

精简 switch 语句中缩进界级别的最好方式就是将"switch"和其下级的"case"放在同一列,而不是双重缩进"case"标签。例如:

不要将多个语句放在同一行,除非你要掩饰什么:

同样也不要将多个赋值放在同一行。内核编程范式超简单。避免复杂的表达式。

还有一个潜规则,是 Kconfig 推荐的,永远不要用空格缩进,上面的例子是故意的。找一个合适的编辑器,记得不要在行末留有空格。

第二章:换行编程范式的意义在于使用常见工具时的可阅读和可维护性。行的长度限制为80列,这是强烈推荐的设置。

多于80列的语句将被分为合适的数块。子句应该永远比主句短,且比主句更靠右侧。这对有较长参数表的函数声明同样有效。长字符串同样也被打断为短字符串。这样做能在超过80列时提高可阅读性,且不会隐藏信息

第三章:大括号和空格

关于 C 风格编程的另一个议点就是大括号。跟缩进值不同,大括号的放置并没有技术因素在内,但“先贤“ Kernighan 和 Ritchie 展示为我们的最好方式,是将左大括号放置在行末尾。而右大括号放置在行首,如下:

对非函数的语句块也是如此(if、switch、for、while、do)。例如:

当然那,有一个特殊的例外, 即函数:它的左大括号在新行的行首,如下:

全世界有不同意见的人都认为此不一致的地方——好吧——很是缺乏一致性,不过只要是能正常思考的都知道《C程序设计语言(第一版)》中是right而《C程序设计语言(第二版)》中则是 right。无论如何,函数都是特殊的(在 C 语言中你不能嵌套定义它们)。

注意,右大括号单独一行,除非后面跟着的是同一个语句。例如 do 语句中的 "while"或 if 语句中的 "else" 如下:

阐述:K&R,《C程序设计语言》一书的缩写。

同时要注意,这种放置大括号的方式能够在不影响可读性的同时,有效减少空行(或近乎空行)的数量。因此,你不许要刷新资源就可以看倒更多行(想想一下只能显示25行的终端窗口),且你能够有空多的空行来安置注释。

只有一行语句时不用添加多余的大括号。

判断语句中只有一个分支为单行语句是,不支持这样用,你需要在所有分支中都加入大括号。

3.1:空格

linux内核风格下的空格,其实际应用主要是取决于函数标识符的使用。大多数函数在其标识符后面会加上空格。当然,sizeof, typeof, alignof,和 __attribute__,像这样的长得像函数(但是因为不需要,所以经常屁股后面不跟着圆括号。例如:"sizeof info"如果在 "struct fileinfo info;"这个声明之后……木有括号……)的,就不需要加空格了。

因此你就知道,在如下关键字后面加个空格:

if, switch, case, for, do, while

而sizeof, typeof, alignof, or__attribute__后面就免了吧,例如

当声明指针或者声明一个返回指针的函数时,最好是在把个小小的“*”离着标识符(不论是变量常量还是函数)近一点,而不是和数据类型近一点,如:

在双目或者三目运算符周围(左边和右边)用上空格——他们包括(译者注:可能不止,并未对此进行仔细检查):

= + - <  > * / % | & ^ <=  >= == != ? :

但是单目运算符就算了,比如这么几个家伙(译者注:同上,未作检查):

& * + - ~ ! sizeof typeof alignof __attribute__ defined还有几个特殊的,比如自增自减运算符,和他们进行运算的变量标识符中间(译者注:原文这里是说,前后都不用加空格)不用加空格。就是这两个家伙:

++ --

然后,“.”和“->”这两个运算符,加括号是作死的行为,你不这么想么?

别在一行的末尾留几个空格。一些具有智能缩进功能的编辑器会在新行的开头适当的插上空格,然后你就可以立即继续写你的程序。但是部分编辑器不会自动删除你程序每一行末尾的空格(虽然你的程序在那几个空格之前已经结束了),甚至这会产生一个完全空白的行,期间充斥着空格这种可恶的东西。

Git在这种情况下会对你进行警告,并提醒你是否由它来为你消灭这些恼人的小东西;但是这种修补总是比不上你自己进行的修补,如果你让Git干了太多这样的活,可能导致你程序行的错乱(所谓进退失据)。

第四章: 命名

C 语言是粗犷的,你的命名同样如此。与 Modula-2 和 Pascal 不同,C 程序员不使用类似 ThisVariableIsATemporaryCounter 这样有趣的命名。C 程序员会将变量命名为类似 "tmp"的名字,这种名字比较好写,且不难理解。

当然,虽然混合大小写的难以让人接受,但对于全局变量,一个描述性的名字却是必须的。调用一个名为 "foo" 全局函数显然是在找不自在。

全局变量(只有你真正需要的时候,再用它)需要一个描述性的名字,全局函数也是。如果你有一个计算活跃用户数量的函数,那么命名其为 "count_active_users()" 或者类似的名字,而非"cntusr()".

将函数类型添加到其名字中(即匈牙利命名法)是有害大脑的——编译器知道、也会检查它的,这只能混淆程序员。所以微软才会生产那么多充满BUG的程序。

局部变量的名字应当简洁了当。如果在循环中需要一些随机数字,你大可以命名其为 "i" 。只要不会产生歧义,命名为 "loop_counter" 毫无意义。同样的,"tmp" 可以是任何类型的临时变量。

如果你担心弄混局部变量的名字,那你有另一个问题:函数增长荷尔蒙失调综合症。

第5章: Typedefs

不要傻呼呼地使用像"vps_t"这样的变量类型.

使用typedef来重定义已有结构体和指针本身就是个错误. 当你在源代码中见到这样的定义:

vps_t a;

天知道a到底是个什么东西!

如果你看到这样的定义:

struct virtual_container *a;

你完全可以一目然: 哦, a是一个指向...的指针.

多数人都觉得typedefs可以提高可阅读性, 但真理往往掌握在少数人手中. Typedefs只有在如下情况下有用:

(a) 需要被封装起来的对象(你本来就打算隐藏起类型信息)

如: "pte_t"这种类型. 封装出这样的类型本来就只打算让特定的"访问函数"才能访问.

请注意: 封装以及"访问函数"本来就不是什么好东西. The reason we have them for things like pte_t etc. is that there really is absolutely _zero_ portably accessible information there.

(b) 定长的整数类型. 这样可以在避免在某些情况下, 搞不清楚到底用的是int还是long, 把你自己搞晕!

u8/u16/u32都是完美的typdefs, 尽管更应该它们归结至规则(d)下.

再次重申: 这样定义必须要有合理的理由. 如果某个变量本来就是unsigned long类型, 你硬要它定义成这样,你就是SB了:

typedef unsigned long myflags_t;

如果你有明确的理由, 在某种情形下变量是unsigned int类型, 而在另外的情形下又要变身成为unsigned long类型, 那就尽管去typedef.

(c) 当你需要使用kernel的sparse工具做变量类型检查时, 你也可以typedef一个类型.

(d)对于特殊情况下的某些c99标准的新类型

你的大脑和眼睛只需要很短的时间就可以习惯像'uint32_t'这样的新类型,虽然有的人反对这宗用法。

因此,虽然对于你的新代码来说,linux独有的'u8/u16/u32/u64'类型并不是强制的,但是他们也是与标准类型等价的。

当编辑现有代码时,如果其中已经使用了某一种类型名规范,你应该遵循原样,使用与之相同的类型名。

(e)用户空间中的类型安全

对于某些结构,显然我们不能使用c99标准的类型,不能使用上述的‘u32’,因此咱干脆在结构中使用'_u32'或者类似的类型好了。

也许还有其它情况,但基本规则是,除非你很清除符合某一条规则,否则永远不要使用typedef。

通常,一个指针或是一个含有元素的结构体,若能直接访问,永远不是typedef。

第6章:函数

函数这种东西,应该小而精,换句话说,只是专心的做一件事情一直到底。如果你把它赤身裸体的展示于屏幕之上,你应该在两个屏幕(这里一个屏幕的大小根据ISO/ANSI标准应该是80X24的)之内就可以看完它。

函数的长度和缩进程度和它的复杂程度是成反比的。所以,如果你的函数确实单纯(译者注:是萌妹子那样的单纯不?)而简单,比如用一个长长的switch-case语句来做点简简单单的事情来处理一些单单纯纯的情况,来吧,咱把函数写再长一点。

相反的,如果你的函数相当的复杂,复杂到你严重怀疑一个普普通通的不想你一样天才的高中学生看不懂……返工吧,把函数缩短缩短再缩短,不要犹豫,多造几个辅助函数并给他们几个一看即知的名字,以减少函数复杂性。(当然,如果你觉得这个函数太关键了,如果拆开了写肯定会影响整个程序的性能,那你干脆内联,用那个内联函数或者使用编译器的内联功能)

规范对于函数的另外一个要求是关于局部变量的个数的:最多5-10个。就算你是天才,你的脑子一般也就能轻松关注7个变量,再多了就绝对会出现一些你意想不到的错误(谁叫你一心多用来着)。好吧,就算你是天才,如果还想明白你在两周之前所写的那些程序的话,还是遵守这些规范吧。

就源代码来说,函数与函数的原型之间应该有一个空白行作为分隔。如果该函数在其他文件中被引用,那么他的EXPORT*宏应当和函数最后一行的那个大括号中间没有任何空格。例如:

另外,在函数原型中,当声明参量时应该将参量的类型和标识符放到一起,虽然c语言本身并不要求这种形式,但是在linux kernal里面是要求的——目的是增加每一行代码的信息量。

章7:集中于一处退出函数

虽然很多人不提倡,但是我们这里要经常使用goto进行无条件的跳转。

当函数有很多个出口,使用goto把这些出口集中到一处是很方便的,特别是函数中有许多重复的清理工作的时候。

理由是:

-无条件跳转易于理解

-可以减少嵌套

-可以避免那种忘记更新某一个出口点的问题

-算是帮助编译器做了代码优化

第8章:注释

有注释当然是好的,但是注释太多就很恶心了。千万不要在注释里面解释你的程序怎么运行的。相对于尝试用注释解释清楚你那恶心的代码,你还不如就写个清晰易懂(译者注:就是小而精,萌妹子一样单纯的~)的函数。

一般的,你的注释是用来说明这段代码是“干啥的”,而不是“怎么干的”。另外,别把注释放到你的函数体里面(译者注:把我放到妹子的怀抱里吧!):如过你的函数确实复杂到需要用注释来分隔成几段,回第六章擦亮眼睛再看两遍(译者注:那一段正好也是我翻译的)。以可以用几个小注释来提醒大家一些东西(“写的好~”或者“写的真tm糟糕”),但是就不要自取其辱评论自己的东西了……最后,仍然提醒你,一定是把注释安放在函数的前面,然后简单写下这段函数式干啥的,如果可能,你倒是不妨提及为什么你要这样做。

当给kernal api函数注释的时候,请使用kernal-doc格式。该格式的细节你可以参考这两个文件:Documentation/kernel-doc-nano-HOWTO.txt和scripts/kernel-doc(译者注:这个文件路径应当是指内核源码中的路径)

linux当中的注释是c89格式("/* ... */")的,而不是c99中新近添加的"// ..."

多于一行(多行)的注释应当准从以下格式:

该格式对于注释标识符(常量,变量,函数等)同样适用。换句话说,你最好不要再一行里面同时声明很多个标识符(无论是用逗号还是分号隔开都是不推荐的),一行一个就可以了。这样你就可以在每一行对每一个标识符进行解释。

第九章:内存分配

内核提供了下列通用内存分配器:kmalloc()、kzalloc()、kcalloc()、vmalloc()、和 vzalloc()。 更多信息,请参阅的 API 文档。

传递一个结构体大小的最好方式如下:

另外一种传递方式中,sizeof的操作数是结构体的名字,这样有损可读性,并会在指针类型改变,但传递给内存分配器的大小没有变化时导致BUG。强制转换返回的void指针是冗余的。C语言本身保证了从void指针到其他任何指针类型的转换。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    87

    文章

    10991

    浏览量

    206736
  • C语言
    +关注

    关注

    180

    文章

    7530

    浏览量

    128727
  • 编辑器
    +关注

    关注

    1

    文章

    788

    浏览量

    30196

原文标题:这是一篇描述 linux 内核首选编码样式的文档

文章出处:【微信号:gh_c472c2199c88,微信公众号:嵌入式微处理器】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Linux内核编码风格(编程代码风格推荐)

    半天没理解的程序。后来直接用indent -kr -i8给他转换格式来看了。特此转过来一个关于代码风格的帖子分享一下~Linux内核编码风格这是一份简短的,描述linux
    发表于 08-24 09:45

    S32K3 uC有首选编译器吗?

    嗨,我想知道,S32K3 uC有首选编译器吗?有几个选择,gcc,greenhill,IAR,看S32DS介绍的时候可以和不同的编译器交互。但是我问自己,在使用这个 uC 时,是否有首选的编译器?
    发表于 03-15 08:26

    Linux内核教程

    本章学习目标掌握LINUX内核版本的含义理解并掌握进程的概念掌握管道的概念及实现了解内核的数据结构了解LINUX内核的算法掌握
    发表于 04-10 16:59 0次下载

    嵌入式Linux内核裁剪与编译_s5pv210

    有关linux内核文档,很好理解的一份文档比较详细
    发表于 11-30 15:34 9次下载

    linux内核启动内核解压过程分析

    linux启动时内核解压过程分析,一份不错的文档,深入了解内核必备
    发表于 03-09 13:39 1次下载

    Linux内核文档:ARM-启动

    Linux内核文档:ARM-启动
    发表于 10-30 10:15 6次下载
    <b class='flag-5'>Linux</b><b class='flag-5'>内核</b><b class='flag-5'>文档</b>:ARM-启动

    linux内核是什么_linux内核学习路线

    Linux内核是一个操作系统(OS)内核,本质上定义为类Unix。它用于不同的操作系统,主要是以不同的Linux发行版的形式。Linux
    发表于 09-16 15:49 2385次阅读

    linux内核参数设置_linux内核的功能有哪些

    本文主要阐述了linux内核参数设置及linux内核的功能。
    发表于 09-17 14:40 1220次阅读
    <b class='flag-5'>linux</b><b class='flag-5'>内核</b>参数设置_<b class='flag-5'>linux</b><b class='flag-5'>内核</b>的功能有哪些

    Linux内核首选代码风格应该如何设置

    这是一个简短的文档,描述了Linux内核首选代码风格。代码风格是因人而异的,而且我不愿意把我的观点强加给任何人,不过这里所讲述的是我必须要维护的代码所遵守的风格,并且我也希望绝大多数
    发表于 11-04 17:17 6次下载
    <b class='flag-5'>Linux</b><b class='flag-5'>内核</b>的<b class='flag-5'>首选</b>代码风格应该如何设置

    嵌入式LINUX系统内核内核模块调试教程

    文档的主要内容详细介绍的是嵌入式LINUX系统内核内核模块调试教程。
    发表于 11-06 17:32 21次下载
    嵌入式<b class='flag-5'>LINUX</b>系统<b class='flag-5'>内核</b>和<b class='flag-5'>内核</b>模块调试教程

    动手编译Linux内核的教程免费下载

    文档的主要内容详细介绍的是动手编译Linux内核的教程免费下载。
    发表于 11-26 17:01 14次下载

    Linux内核的编译与运行

    文档的主要内容详细介绍的是Linux内核的编译与运行免费下载。
    发表于 03-25 13:48 10次下载

    Linux内核】从小小的宏定义窥探Linux内核的精妙设计

    Linux内核】从小小的宏定义窥探Linux内核的精妙设计
    的头像 发表于 08-31 13:30 1641次阅读

    SRRC证书样式和代码编码规则即将施行

    为优化无线电发射设备型号核准证书样式和代码编码规则,根据《无线电发射设备管理规定》,近日,工业和信息化部修订发布了《无线电发射设备型号核准证书样式》和《无线电发射设备型号核准代码编码
    的头像 发表于 10-14 16:50 387次阅读
    SRRC证书<b class='flag-5'>样式</b>和代码<b class='flag-5'>编码</b>规则即将施行

    兆芯正引入Linux首选内核调度技术,优化性能

    近期,兆芯工程团队亦在致力于将首选内核调度技术引进Linux系统中。他们试图通过提议的Linux内核补丁,利用已有的ACPI功能来辨别每个核
    的头像 发表于 12-29 14:30 212次阅读
    兆芯正引入<b class='flag-5'>Linux</b><b class='flag-5'>首选</b><b class='flag-5'>内核</b>调度技术,优化性能