Linux内核编码规范

这是一个简短的文档,描述了linux内核的首选代码风格。代码风格是因人而异的,并且我不肯意把个人观点强加给任何人,不过这里所讲述的是我必需要维护的代码所遵照的风格,而且我也但愿绝大多数其余代码也能遵照这个风格。请在写代码时至少考虑一下本文所述的风格。linux

首先,我建议你打印一份GNU代码规范,而后不要读它。烧了它,这是一个具备重大象征性意义的动做。git

无论怎样,如今咱们开始:程序员


第一章:缩进编程

制表符是8个字符,因此缩进也是8个字符。有些异端运动试图将缩进变为4(乃至2)个字符深,这几乎至关于尝试将圆周率的值定义为3。vim

理由:缩进的所有意义就在于清楚的定义一个控制块起止于何处。尤为是当你盯着你的屏幕连续看了20小时以后,你将会发现大一点的缩进会使你更容易分辨缩进。数组

如今,有些人会抱怨8个字符的缩进会使代码向右边移动的太远,在80个字符的终端屏幕上就很难读这样的代码。这个问题的答案是,若是你须要3级以上的缩进,无论用何种方式你的代码已经有问题了,应该修正你的程序。缓存

简而言之,8个字符的缩进可让代码更容易阅读,还有一个好处是当你的函数嵌套太深的时候能够给你警告。留心这个警告。安全

在switch语句中消除多级缩进的首选的方式是让“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;

    }


不要把多个语句放在一行里,除非你有什么东西要隐藏:

    if (condition) do_this;

      do_something_everytime;

也不要在一行里放多个赋值语句。内核代码风格超级简单。就是避免可能致使别人误读的表达式。

除了注释、文档和Kconfig以外,不要使用空格来缩进,前面的例子是例外,是有意为之。

选用一个好的编辑器,不要在行尾留空格。


第二章:把长的行和字符串打散

代码风格的意义就在于使用日常使用的工具来维持代码的可读性和可维护性。

每一行的长度的限制是80列,咱们强烈建议您遵照这个惯例。

长于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;

}

第三章:大括号和空格的放置

C语言风格中另一个常见问题是大括号的放置。和缩进大小不一样,选择或弃用某种放置策略并无多少技术上的缘由,不过首选的方式,就像Kernighan和Ritchie展现给咱们的,是把起始大括号放在行尾,而把结束大括号放在行首,因此:

    if (x is true) {

        we do y

    }

这适用于全部的非函数语句块(if、switch、for、while、do)。好比:

    switch (action) {

    case KOBJ_ADD:

        return "add";

    case KOBJ_REMOVE:

        return "remove";

    case KOBJ_CHANGE:

        return "change";

    default:

        return NULL;

    }

不过,有一个例外,那就是函数:函数的起始大括号放置于下一行的开头,因此:

    int function(int x)

    {

        body of function

    }

全世界的异端可能会抱怨这个不一致性是……呃……不一致的,不过全部思惟健全的人都知道(a)K&R是_正确的_,而且(b)K&R是正确的。此外,无论怎样函数都是特殊的(在C语言中,函数是不能嵌套的)。

注意结束大括号独自占据一行,除非它后面跟着同一个语句的剩余部分,也就是do语句中的“while”或者if语句中的“else”,像这样:

    do {

        body of do-loop

    } while (condition);

    if (x == y) {

        ..

    } else if (x > y) {

        ...

    } else {

        ....

    }

理由:K&R。

也请注意这种大括号的放置方式也能使空(或者差很少空的)行的数量最小化,同时不失可读性。所以,因为你的屏幕上的新行是不可再生资源(想一想25行的终端屏幕),你将会有更多的空行来放置注释。

当只有一个单独的语句的时候,不用加没必要要的大括号。

if (condition)

    action();

这点不适用于自己为某个条件语句的一个分支的单独语句。这时须要在两个分支里都使用大括号。

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__这些关键字以后放空格。例如,

    s = sizeof(struct file);

不要在小括号里的表达式两侧加空格。这是一个反例:

    s = sizeof( struct file );

当声明指针类型或者返回指针类型的函数时,“*”的首选使用方式是使之靠近变量名或者函数名,而不是靠近类型名。例子:

    char *linux_banner;

    unsigned long long memparse(char *ptr, char **retptr);

    char *match_strdup(substring_t *s);

在大多数二元和三元操做符两侧使用一个空格,例以下面全部这些操做符:

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

可是一元操做符后不要加空格:

    & * + - ~ ! sizeof typeof alignof __attribute__ defined

后缀自加和自减一元操做符前不加空格:

    ++ --

前缀自加和自减一元操做符后不加空格:

    ++ --

“.”和“->”结构体成员操做符先后不加空格。

不要在行尾留空白。有些能够自动缩进的编辑器会在新行的行首加入适量的空白,而后你就能够直接在那一行输入代码。不过假如你最后没有在那一行输入代码,有些编辑器就不会移除已经加入的空白,就像你故意留下一个只有空白的行。包含行尾空白的行就这样产生了。

当git发现补丁包含了行尾空白的时候会警告你,而且能够应你的要求去掉行尾空白;不过若是你是正在打一系列补丁,这样作会致使后面的补丁失败,由于你改变了补丁的上下文。


第四章:命名

C是一个简朴的语言,你的命名也应该这样。和Modula-2和Pascal程序员不一样,C程序员不使用相似ThisVariableIsATemporaryCounter这样华丽的名字。C程序员会称那个变量为“tmp”,这样写起来会更容易,并且至少不会令其难于理解。

不过,虽然混用大小写的名字是不提倡使用的,可是全局变量仍是须要一个具描述性的名字。称一个全局函数为“foo”是一个难以饶恕的错误。

全局变量(只有当你真正须要它们的时候再用它)须要有一个具描述性的名字,就像全局函数。若是你有一个能够计算活动用户数量的函数,你应该叫它“count_active_users()”或者相似的名字,你不该该叫它“cntuser()”。

在函数名中包含函数类型(所谓的匈牙利命名法)是脑子出了问题——编译器知道那些类型并且可以检查那些类型,这样作只能把程序员弄糊涂了。难怪微软老是制造出有问题的程序。

本地变量名应该简短,并且可以表达相关的含义。若是你有一些随机的整数型的循环计数器,它应该被称为“i”。叫它“loop_counter”并没有益处,若是它没有被误解的可能的话。相似的,“tmp”能够用来称呼任意类型的临时变量。

若是你怕混淆了你的本地变量名,你就遇到另外一个问题了,叫作函数增加荷尔蒙失衡综合症。请看第六章(函数)。


第五章:Typedef

不要使用相似“vps_t”之类的东西。

对结构体和指针使用typedef是一个错误。当你在代码里看到:

    vps_t a;

这表明什么意思呢?

相反,若是是这样

    struct virtual_container *a;

你就知道“a”是什么了。

不少人认为typedef“能提升可读性”。实际不是这样的。它们只在下列状况下有用:

(a) 彻底不透明的对象(这种状况下要主动使用typedef来隐藏这个对象其实是什么)。

     例如:“pte_t”等不透明对象,你只能用合适的访问函数来访问它们。

     注意!不透明性和“访问函数”自己是很差的。咱们使用pte_t等类型的缘由在于真的是彻底没有任何共用的可访问信息。

(b) 清楚的整数类型,如此,这层抽象就能够帮助消除究竟是“int”仍是“long”的混淆。

     u8/u16/u32是彻底没有问题的typedef,不过它们更符合类别(d)而不是这里。

     再次注意!要这样作,必须事出有因。若是某个变量是“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。


第六章:函数

函数应该简短而漂亮,而且只完成一件事情。函数应该能够一屏或者两屏显示完(咱们都知道ISO/ANSI屏幕大小是80x24),只作一件事情,并且把它作好。

一个函数的最大长度是和该函数的复杂度和缩进级数成反比的。因此,若是你有一个理论上很简单的只有一个很长(可是简单)的case语句的函数,并且你须要在每一个case里作不少很小的事情,这样的函数尽管很长,但也是能够的。

不过,若是你有一个复杂的函数,并且你怀疑一个天分不是很高的高中一年级学生可能甚至搞不清楚这个函数的目的,你应该严格的遵照前面提到的长度限制。使用辅助函数,并为之取个具描述性的名字(若是你以为它们的性能很重要的话,可让编译器内联它们,这样的效果每每会比你写一个复杂函数的效果要好。)

函数的另一个衡量标准是本地变量的数量。此数量不该超过5-10个,不然你的函数就有问题了。从新考虑一下你的函数,把它分拆成更小的函数。人的大脑通常能够轻松的同时跟踪7个不一样的事物,若是再增多的话,就会糊涂了。即使你聪颖过人,你也可能会记不清你2个星期前作过的事情。

在源文件里,使用空行隔开不一样的函数。若是该函数须要被导出,它的EXPORT*宏应该紧贴在它的结束大括号之下。好比:

int system_is_up(void)

{

    return system_state == SYSTEM_RUNNING;

}

EXPORT_SYMBOL(system_is_up);

在函数原型中,包含函数名和它们的数据类型。虽然C语言里没有这样的要求,在Linux里这是提倡的作法,由于这样能够很简单的给读者提供更多的有价值的信息。


第七章:集中的函数退出途径

虽然被某些人声称已通过时,可是goto语句的等价物仍是常常被编译器所使用,具体形式是无条件跳转指令。

当一个函数从多个位置退出而且须要作一些通用的清理工做的时候,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;

}

第八章:注释

注释是好的,不过有过分注释的危险。永远不要在注释里解释你的代码是如何运做的:更好的作法是让别人一看你的代码就能够明白,解释写的不好的代码是浪费时间。

通常的,你想要你的注释告诉别人你的代码作了什么,而不是怎么作的。也请你不要把注释放在一个函数体内部:若是函数复杂到你须要独立的注释其中的一部分,你极可能须要回到第六章看一看。你能够作一些小注释来注明或警告某些很聪明(或者槽糕)的作法,但不要加太多。你应该作的,是把注释放在函数的头部,告诉人们它作了什么,也能够加上它作这些事情的缘由。

当注释内核API函数时,请使用kernel-doc格式。请看

Documentation/kernel-doc-nano-HOWTO.txt和scripts/kernel-doc以得到详细信息。

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.

     */

注释数据也是很重要的,无论是基本类型仍是衍生类型。为了方便实现这一点,每一行应只声明一个数据(不要使用逗号来一次声明多个数据)。这样你就有空间来为每一个数据写一段小注释来解释它们的用途了。


第九章:你已经把事情弄糟了

这没什么,咱们都是这样。可能你的使用了很长时间Unix的朋友已经告诉你“GNU emacs”能自动帮你格式化C源代码,并且你也注意到了,确实是这样,不过它所使用的默认值和咱们想要的相去甚远(实际上,甚至比随机打的还要差——无数个猴子在GNU emacs里打字永远不会创造出一个好程序)(译注:请参考Infinite Monkey Theorem)

因此你要么放弃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 tab-width 8)

(setq indent-tabs-mode t)

(setq c-basic-offset 8))

这样就定义了M-x linux-c-mode命令。当你hack一个模块的时候,若是你把字符串

-*- linux-c -*-放在头两行的某个位置,这个模式将会被自动调用。若是你但愿在你修改

/usr/src/linux里的文件时魔术般自动打开linux-c-mode的话,你也可能须要添加

(setq auto-mode-alist (cons '("/usr/src/linux.*/.*\\.[ch]$" . linux-c-mode)

            auto-mode-alist))

到你的.emacs文件里。

不过就算你尝试让emacs正确的格式化代码失败了,也并不意味着你失去了一切:还能够用“indent”。

不过,GNU indent也有和GNU emacs同样有问题的设定,因此你须要给它一些命令选项。不过,这还不算太糟糕,由于就算是GNU indent的做者也认同K&R的权威性(GNU的人并非坏人,他们只是在这个问题上被严重的误导了),因此你只要给indent指定选项“-kr -i8”(表明“K&R,8个字符缩进”),或者使用“scripts/Lindent”,这样就能够以最时髦的方式缩进源代码。

“indent”有不少选项,特别是从新格式化注释的时候,你可能须要看一下它的手册页。不过记住:“indent”不能修正坏的编程习惯。


第十章:Kconfig配置文件

对于遍及源码树的全部Kconfig*配置文件来讲,它们缩进方式与C代码相比有所不一样。紧挨在“config”定义下面的行缩进一个制表符,帮助信息则再多缩进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.

仍然被认为不够稳定的功能应该被定义为依赖于“EXPERIMENTAL”:

config SLUB

    depends on EXPERIMENTAL && !ARCH_USES_SLAB_PAGE_STRUCT

    bool "SLUB (Unqueued Allocator)"

    ...

而那些危险的功能(好比某些文件系统的写支持)应该在它们的提示字符串里显著的声明这一点:

config ADFS_FS_RW

    bool "ADFS write support (DANGEROUS)"

    depends on ADFS_FS

    ...

要查看配置文件的完整文档,请看Documentation/kbuild/kconfig-language.txt。


第十一章:数据结构

若是一个数据结构,在建立和销毁它的单线执行环境以外可见,那么它必需要有一个引用计数器。内核里没有垃圾收集(而且内核以外的垃圾收集慢且效率低下),这意味着你绝对须要记录你对这种数据结构的使用状况。

引用计数意味着你可以避免上锁,而且容许多个用户并行访问这个数据结构——而不须要担忧这个数据结构仅仅由于暂时不被使用就消失了,那些用户可能不过是沉睡了一阵或者作了一些其余事情而已。

注意上锁不能取代引用计数。上锁是为了保持数据结构的一致性,而引用计数是一个内存管理技巧。一般两者都须要,不要把两个搞混了。

不少数据结构实际上有2级引用计数,它们一般有不一样“类”的用户。子类计数器统计子类用户的数量,每当子类计数器减至零时,全局计数器减一。

这种“多级引用计数”的例子能够在内存管理(“struct mm_struct”:mm_users和mm_count)和文件系统(“struct super_block”:s_count和s_active)中找到。

记住:若是另外一个执行线索能够找到你的数据结构,可是这个数据结构没有引用计数器,这里几乎确定是一个bug。


第十二章:宏,枚举和RTL

用于定义常量的宏的名字及枚举里的标签须要大写。

#define CONSTANT 0x12345

在定义几个相关的常量时,最好用枚举。

宏的名字请用大写字母,不过形如函数的宏的名字能够用小写字母。

通常的,若是能写成内联函数就不要写成像函数的宏。

含有多个语句的宏应该被包含在一个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)

很是很差。它看起来像一个函数,不过却能致使“调用”它的函数退出;不要打乱读者大脑里的语法分析器。

2) 依赖于一个固定名字的本地变量的宏:

#define FOO(val) bar(index, val)

可能看起来像是个不错的东西,不过它很是容易把读代码的人搞糊涂,并且容易致使看起来不相关的改动带来错误。

3) 做为左值的带参数的宏: FOO(x) = y;若是有人把FOO变成一个内联函数的话,这种用法就会出错了。

4) 忘记了优先级:使用表达式定义常量的宏必须将表达式置于一对小括号以内。带参数的宏也要注意此类问题。

#define CONSTANT 0x4000

#define CONSTEXP (CONSTANT | 3)

cpp手册对宏的讲解很详细。Gcc internals手册也详细讲解了RTL(译注:register

transfer language),内核里的汇编语言常常用到它。


第十三章:打印内核消息

内核开发者应该是受过良好教育的。请必定注意内核信息的拼写,以给人以好的印象。不要用不规范的单词好比“dont”,而要用“do not”或者“don't”。保证这些信息简单、明了、无歧义。

内核信息没必要以句号(译注:英文句号,即点)结束。

在小括号里打印数字(%d)没有任何价值,应该避免这样作。

里有一些驱动模型诊断宏,你应该使用它们,以确保信息对应于正确的

设备和驱动,而且被标记了正确的消息级别。这些宏有:dev_err(), dev_warn(),

dev_info()等等。对于那些不和某个特定设备相关连的信息,定义了

pr_debug()和pr_info()。

写出好的调试信息能够是一个很大的挑战;当你写出来以后,这些信息在远程除错的时候就会成为极大的帮助。当DEBUG符号没有被定义的时候,这些信息不该该被编译进内核里(也就是说,默认地,它们不该该被包含在内)。若是你使用dev_dbg()或者pr_debug(),就能自动达到这个效果。不少子系统拥有Kconfig选项来启用-DDEBUG。还有一个相关的惯例是使用VERBOSE_DEBUG来添加dev_vdbg()消息到那些已经由DEBUG启用的消息之上。


第十四章:分配内存

内核提供了下面的通常用途的内存分配函数:kmalloc(),kzalloc(),kcalloc()和vmalloc()。请参考API文档以获取有关它们的详细信息。

传递结构体大小的首选形式是这样的:

    p = kmalloc(sizeof(*p), ...);

另一种传递方式中,sizeof的操做数是结构体的名字,这样会下降可读性,而且可能会引入bug。有可能指针变量类型被改变时,而对应的传递给内存分配函数的sizeof的结果不变。

强制转换一个void指针返回值是多余的。C语言自己保证了从void指针到其余任何指针类型的转换是没有问题的。


第十五章:内联弊病

有一个常见的误解是内联函数是gcc提供的可让代码运行更快的一个选项。虽然使用内联函数有时候是恰当的(好比做为一种替代宏的方式,请看第十二章),不过不少状况下不是这样。inline关键字的过分使用会使内核变大,从而使整个系统运行速度变慢。由于大内核会占用更多的指令高速缓存(译注:一级缓存一般是指令缓存和数据缓存分开的)并且会致使pagecache的可用内存减小。想象一下,一次pagecache未命中就会致使一次磁盘寻址,将耗时5毫秒。5毫秒的时间内CPU能执行不少不少指令。

一个基本的原则是若是一个函数有3行以上,就不要把它变成内联函数。这个原则的一个例外是,若是你知道某个参数是一个编译时常量,并且由于这个常量你肯定编译器在编译时能优化掉你的函数的大部分代码,那仍然能够给它加上inline关键字。kmalloc()内联函数就是一个很好的例子。

人们常常主张给static的并且只用了一次的函数加上inline,如此不会有任何损失,由于没有什么好权衡的。虽然从技术上说这是正确的,可是实际上这种状况下即便不加inline gcc也能够自动使其内联。并且其余用户可能会要求移除inline,由此而来的争论会抵消inline自身的潜在价值,得不偿失。


第十六章:函数返回值及命名

函数能够返回不少种不一样类型的值,最多见的一种是代表函数执行成功或者失败的值。这样的一个值能够表示为一个错误代码整数(-Exxx=失败,0=成功)或者一个“成功”布尔值(0=失败,非0=成功)。

混合使用这两种表达方式是难于发现的bug的来源。若是C语言自己严格区分整形和布尔型变量,那么编译器就可以帮咱们发现这些错误……不过C语言不区分。为了不产生这种bug,请遵循下面的惯例:

    若是函数的名字是一个动做或者强制性的命令,那么这个函数应该返回错误代码整

    数。若是是一个判断,那么函数应该返回一个“成功”布尔值。

好比,“add work”是一个命令,因此add_work()函数在成功时返回0,在失败时返回-EBUSY。

相似的,由于“PCI device present”是一个判断,因此pci_dev_present()函数在成功找到一个匹配的设备时应该返回1,若是找不到时应该返回0。

全部导出(译注:EXPORT)的函数都必须遵照这个惯例,全部的公共函数也都应该如此。私有(static)函数不须要如此,可是咱们也推荐这样作。

返回值是实际计算结果而不是计算是否成功的标志的函数不受此惯例的限制。通常的,他们经过返回一些正常值范围以外的结果来表示出错。典型的例子是返回指针的函数,他们使用NULL或者ERR_PTR机制来报告错误。


第十七章:不要从新发明内核宏

头文件include/linux/kernel.h包含了一些宏,你应该使用它们,而不要本身写一些它们的变种。好比,若是你须要计算一个数组的长度,使用这个宏

#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

相似的,若是你要计算某结构体成员的大小,使用

#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))

还有能够作严格的类型检查的min()和max()宏,若是你须要可使用它们。你能够本身看看那个头文件里还定义了什么你能够拿来用的东西,若是有定义的话,你就不该在你的代码里本身从新定义。


第十八章:编辑器模式行和其余须要罗嗦的事情

有一些编辑器能够解释嵌入在源文件里的由一些特殊标记标明的配置信息。好比,emacs可以解释被标记成这样的行:

-*- mode: c -*-

或者这样的:

/*

Local Variables:

compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c"

End:

*/

Vim可以解释这样的标记:

/* vim:set sw=8 noet */

不要在源代码中包含任何这样的内容。每一个人都有他本身的编辑器配置,你的源文件不该该覆盖别人的配置。这包括有关缩进和模式配置的标记。人们可使用他们本身定制的模式,或者使用其余能够产生正确的缩进的巧妙方法。

相关文章
相关标签/搜索