风格与指南
通常将主例程定义为 main()。对应的 ANSI 编写方式是 int main(void)(如果不考虑命令行参数的话)或 int main( int argc, char **argv )。ANSI 以前的编译器会省略 void声明,或列出变量名以及紧随其后的声明。空格充分利用水平和垂直空格。缩进和空格间距应反映出代码的块结构。
应将条件运算符的长字符串分割成单独的几行。例如:
if (foo->next==NULL && number < limit && limit <=SIZE
&& node_active(this_input)) {... |
最好改成:
if (foo->next == NULL
&& number < limit && limit <= SIZE
&& node_active(this_input))
{
... |
同样,应将描述得很详细的 for 循环分割成不同的行:
for (curr = *varp, trail = varp;
curr != NULL;
trail = &(curr->next), curr = curr->next )
{
... |
对于其它复杂表达式(如使用三元运算符 :的表达式),最好也将其分割成数行。
z = (x == y)
n + f(x)
: f(y) - n;
|
注释注释应描述正在发生什么事、如何完成它、参数表示什么、使用了哪些全局变量以及任何限制或错误。但要避免不必要的注释。如果代码比较清晰,并且使用了良好的变量名,那么它应该能够较好地说明自身。因为编译器不检查注释,所以不保证它们是正确的。与代码不一致的注释会起到相反的作用。过多的注释会使代码混乱。
下面是一种多余的注释风格:
i=i+1; /* Add one to i */
|
很明显变量 i递增了 1。还有更糟的注释方法:
/************************************
* *
* Add one to i *
* *
************************************/
i=i+1; |
命名约定具有前导和尾随下划线的名称是为系统用途而保留的,不应当用于任何用户创建的名称。约定规定:
- #define 常量应全部大写。
- enum 常量应以大写字母开头或全部大写。
- 函数、类型定义(typedef)和变量名以及结构(struct)、联合(union)和枚举(enum)标记名称应小写。
为清晰起见,避免使用仅在大小写上有区别的名称,如 foo 和 Foo。同样,避免使用 foobar 和 foo_bar 这样的名称。避免使用看上去相似的名称。在许多终端和打印机上,“l”、“1”和“I”看上去非常相似。使用名为“l”的变量非常不明智,因为它看上去非常象常量“1”。
变量名选择变量名时,长度不重要,但清晰的表达很重要。长名称可用于全局变量,因为它不常用,而将在每行循环上要使用的数组下标命名为 i 就完全够了。如果使用“index”或“elementnumber”的话,不仅输入得更多,而且会使计算的细节不明确。如果使用长变量名,有时候会使代码更难理解。比较:
for(i=0 to 100)
array[i]=0 |
和
for(elementnumber=0 to 100)
array[elementnumber]=0;
|
函数名函数名应反映函数执行什么操作以及返回什么内容。函数在表达式中使用,通常用于 if子句,因此它们的意图应一目了然。例如:
没有帮助作用,因为它没有告诉我们 checksize 是在出错时返回 true 还是在不出错时返回 true;而
则使函数的意图很明确。
声明所有的外部数据声明前都应加上 extern关键字。
“指针”限定符“*”应紧邻变量名而不是类型。例如,应使用
而不是
后一条语句没有错,但可能不是我们期望的,因为没有将“t”和“u”声明为指针。
头文件头文件应按功能组织在一起,即,对单独子系统的声明应在单独的头文件中。此外,当代码从一个平台移植到另一个平台时有可能发生更改的声明应位于单独的头文件中。
避免使用与库头文件名相同的专用头文件名。语句 #include "math.h" 如果在当前目录中找不到所期望文件的话,会包括标准库 math 头文件。如果这是您期望的结果,可以注释掉这行 include 语句。
最后说明一点,对头文件使用绝对路径名不是一个好主意。C 编译器的“include-path”选项(在许多系统上为 -I — 大写的 i)是处理众多专用头文件库的首选方法;它允许在不改变源文件的情况下重新组织目录结构。
scanf在重要的应用程序中永远不要使用 scanf。它的错误检测不够完善。请看下面的示例:
#include <stdio.h>
int main(void)
{
int i;
float f;
printf("Enter an integer and a float: ");
scanf("%d %f", &i, &f);
printf("I read %d and %f\n", i, f);
return 0;
} |
测试运行
Enter an integer and a float: 182 52.38
I read 182 and 52.380001
另一个测试运行
Enter an integer and a float: 6713247896 4.4
I read -1876686696 and 4.400000
++ 和 --当对语句中的变量使用递增或递减运算符时,该变量不应在语句中出现一次以上,因为求值的顺序取决于编译器。编写代码时不要对顺序作假设,也不要编写在某一机器上能够如期运作但没有明确定义的行为的代码:
int i = 0, a[5];
a[i] = i++; /* assign to a[0] or a[1] */ |
不要被表面现象迷惑请看以下示例:
while (c == '\t' || c = ' ' || c == '\n')
c = getc(f);
|
乍一看, while子句中的语句似乎是有效的 C 代码。但是,使用赋值运算符而不是比较运算符却产生了语义上不正确的代码。= 的优先级在所有运算符中是最低的,因此将以下列方式解释该语句(为清晰起见添加了括号):