第四章:命名
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。
|