(C语言)编程规范

缩进

"switch"和其下级的"case"放在同一列,而不是双重缩进"case"标签

    switch (suffix) {
    case 'G':
    case 'g':
        mem <<= 30;
        break;
    case 'M':
    case 'm':
        mem <<= 20;
        break;
    case 'K':
    case 'k':
        mem <<= 10;
        /* fall through */
    default:
        break; 
    }

不要将多个语句放在同一行

换行

行的长度限制为80列,这是强烈推荐的设置。
多于80列的语句将被分为合适的数块。子句应该永远比主句短,且比主句更靠右侧
对有较长参数表的函数声明同样有效
长字符串同样也被打断为短字符串

void fun(int a, int b, int c)
{
    if (condition)
        printk(KERN_WARNING "Warning this is a long printk with "
                        "3 parameters a: %u b: %u "
                        "c: %u \n", a, b, c);
    else
        next_statement;
}

大括号和空格

将左大括号放置在行末尾。而右大括号放置在行首
只有一行语句时不用添加多余的大括号

命名

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

typedefs

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

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

vps_t a;

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

如果你看到这样的定义:

struct virtual_container *a; 

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

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

  1. 需要被封装起来的对象(你本来就打算隐藏起类型信息)
    如: "pte_t"这种类型. 封装出这样的类型本来就只打算让特定的"访问函数"才能访问.
    请注意: 封装以及"访问函数"本来就不是什么好东西. The reason we have them for things like pte_t etc. is that there
    really is absolutely zero portably accessible information there.

  2. 定长的整数类型. 这样可以在避免在某些情况下, 搞不清楚到底用的是int还是long, 把你自己搞晕!
    u8/u16/u32都是完美的typdefs, 尽管更应该它们归结至规则(d)下.
    再次重申: 这样定义必须要有合理的理由. 如果某个变量本来就是unsigned long类型, 你硬要它定义成这样,你就是SB了:

typedef unsigned long myflags_t; 

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

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

  2. 对于特殊情况下的某些c99标准的新类型
    你的大脑和眼睛只需要很短的时间就可以习惯像'uint32_t'这样的新类型,虽然有的人反对这宗用法。
    因此,虽然对于你的新代码来说,linux独有的'u8/u16/u32/u64'类型并不是强制的,但是他们也是与标准类型等价的。
    当编辑现有代码时,如果其中已经使用了某一种类型名规范,你应该遵循原样,使用与之相同的类型名。

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

函数

  1. 局部变量个数:5-10个
  2. 简短

集中一处退出函数

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

理由是:

  • 无条件跳转易于理解

  • 可以减少嵌套

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

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

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

    if (buffer == NULL) 
        return -ENOMEM; 

    if (condition1) { 
        while (loop1) { 
            ... 
        } 
        result = 1; 
        goto out; 
    } 
    ... 
out: 
    kfree(buffer); 
    return result; 
} 

注释

写在函数前面说明函数是干啥的。函数里头不要有注释
linux当中的注释是c89格式("/* ... */")的,而不是c99中新近添加的"// ..."

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

/* 
 * 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. 
 */ 

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

宏,枚举和RTL

定义常量的宏名字和枚举变量是大写的
定义一些相关联常量用枚举
全部为大写的宏名称是很好的,但有些和函数相似的宏名称也可以定义为小写的
通常,把内联函数被定义为宏是比较好的
多个语句的宏应该被定义在一个do-while循环体里:

#define macrofun(a, b, c)             \
     do {                             \
         if (a == 5)                  \
             do_this(b, c);           \
     } while (0)

应该避免的情况:

  1. 会改变控制流的宏
#define FOO(x)                    \
     do {                         \
         if (blah(x) < 0)         \
             return -EBUGGERED;   \
     } while(0)

It is a very bad idea. It looks like a function call but exits the "calling"
function; don't break the internal parsers of those who will read the code.
它看起来像一个函数调用,但是它可能会直接使得调用者退出。搞得读代码的人会莫名其妙,为啥在这个地方退出了

  1. 宏依赖奇怪名称的本地变量
#define FOO(val) bar(index, val)

函数返回值或名称

如果函数是一个动作或者一个命令,则成功返回0,失败返回一个整型的错误代码,例如,“add work”是一个命令, 因此add_work()函数返回0表示成功,或者返回-EBUSY表示失败。
如果函数名类似断言,那么它应该返回一个表示是否成功的布尔值。例如,“PCI device present”是一个断言,那么pci_dev_present()函数返回1表示找到匹配的设备,或者返回0表示没找到。

日志调试

不要使用简写,使用 "do not" 或 "don't" 而非 "dont"。保持信息简洁明了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,591评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,448评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,823评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,204评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,228评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,190评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,078评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,923评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,334评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,550评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,727评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,428评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,022评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,672评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,826评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,734评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,619评论 2 354

推荐阅读更多精彩内容