谈谈代码缩进

在有关代码风格的问题中,最为显眼的可以说就是代码的缩进了。所谓缩进,是为了在每一行的代码左端空出一部分长度,使得更加清晰地从外观上看出程序的逻辑结构。先举一个正确缩进的例子:

int kmp_match(char t[], char p[], int flink[], int n, int m)
{
    int i = 0, j = 0;
   
    while(i < n)
    {
        while(j != -1 && p[j] != t[i])
            j = flink[j];
        if(j == m – 1)
            return (i – m + 1);
        i++;
        j++;
    }
    return (-1);
}

我在这里,把有嵌套关系的代码行都采用缩进的方式体现出来了。可以看出,如果在书写代码的同时,能够认真地注意缩进,那么有关嵌套方面的错误、包括大括号配对的错误都不可能出现。假设代码被写成了这个样子:

int kmp_match(char t[], char p[], int flink[], int n, int m)
{int i = 0, j = 0;
while(i < n)
{while(j != -1 && p[j] != t[i])
j = flink[j];
if(j == m – 1)
return (i – m + 1);
i++;
j++;
}
return (-1);
}

你还能一眼看得出来每个 while 循环的具体内容是什么吗?因此,正确地进行缩进会大大提高代码的可读性,下面来说说一些基本的缩进规则。

需要缩进的结构

在遇到有关类、结构、函数或过程、以及枚举等等复杂程序结构的定义的时候,我们通常需要将它的内容缩进一层。在 C/C++/C#/Java 语言中,大括号是一个非常明显的标志,凡是遇到大括号,都应该直接联想到缩进。在 Basic 语言中,Class/End ClassSub/End SubFunction/End FunctionStructure/End StructureEnum/End Enum 等等这类带有“End”结束的结构中的内容都应该缩进。例如:

public class MyClass : MyBase
{
    //
类的内容

    protected int mHandle;
    ...
}

Public Class MyClass Inherits MyBase
    '
类的内容

    Protected mHandle As Integer
    ...
End Class

分支结构(包括 if…else 结构、switch/select…case 结构等)和循环结构(包括 for 结构、while/do…while 结构等)都是存在嵌套关系的,因此从条理清晰的角度来说,它同样应该进行缩进书写。

if(a > b)
{
    // if
子句的结构体内容

    max = a;
    min = b;
}
else
{
    // else
子句的结构体内容
    max = b;
    min = a;
}

If a > b Then
    ' If
子句的结构体内容

    max = a
    min = b
Else
    ' Else
子句的结构体内容
    max = b
    min = a
End If

switch(n)
{
    case 0:
        //
n 0 时的处理内容

        ...
        break;
    case 1:
        //
n 1 时的处理内容
        ...
        break;
    default:
        ...
}

Select Case n
    Case 0
        '
n 0 时的处理内容

        ...
    Case 1
        '
n 1 时的处理内容
        ...
    Case Else
        ...
End Select

for(i = 1; i <= 100; i++)
{
    // for
的循环体

    s += data[i];
    t *= data[i];
}

For i = 1 To 100
    ' For
的循环体

    s = s + data(i)
    t = t * data(i)
Next

i = 0;
while(data[i] != 0)
{
    // while
的循环体

    s += data[i];
    t *= data[i];
    i++;
}

i = 0
While data(i) <> 0
    ' while
的循环体

    s = s + data(i)
    t = t * data(i)
    i = i + 1
Wend

缩进的格式

在编译器中,缩进通常用 TAB 键来控制,它通常对应 2 个或者 4 个空格。同一层次的缩进必须严格对齐。

在大括号语法中,缩进时大括号的写法有不同的几种,个人认为,前面所用的那种左右括号单独一行的写法最为清晰,因为可以最好地反映出括号的配对情况。其它的一些写法有:

// 将左大括号放在结构行某尾
int Sum(int x, int y) {
    //
函数内容
    int s;
    s = x + y;
    return s;
}

// 将左大括号与结构内第一条语句写在一起
int Sum(int x, int y)
{   int s;
    s = x + y;
    return s;
}

特殊的分支循环结构(单行内容)

很多语言中,分支结构(如 if)和循环结构(如 for)的结构体部分只有一条语句时,写法与包含多条语句时稍有不同。在 C/C++/Java/C# 语言中,大括号可以省略,这时,我们还是应该按照它的逻辑关系进行缩进处理:

if(a > b)
    max = a;
else
    max = b;
//
其它语句

printf("%d", max);

for(i = 1; i <= 100; i++)
    s += data[i];
//
其它语句

printf("%d", s);

i = 0;
while(data[i] != 0)
    s += data[i++];
//
其它语句

printf("%d", s);

Basic 中,如果 If 或者 Else 后只有一条语句,就可以与 If/Else 写在同一行中,而不需要 End If 结构。然而那是旧式的写法,从现代意义上来说,建议还是分行书写,并使用 End If 结尾。

长语句换行

有的时候,一条语句会很长,而超出了屏幕的边界。在这种情况下,虽然你可以不换行,但是从外观上来说会显得很不方便。通常,我们都会根据屏幕通常的宽度来对长语句进行换行。换行以后的部分,要相对于原语句缩进一格:

// 这是一条很长的语句:
myvar = myvar1 + myvar2 + myvar3 - myvar4 - myvar5 * myvar6 * myvar7 /
    myvar8 / myvar9 + myvar10 + myvar11 - myvar12 – myvar13 * myvar14 *
    myvar15 / myvar16;
//
后面的语句恢复正常的缩进位置

在换行时,我们通常在一个变量或者常量之前换行,把逗号之类的分隔符、运算符留在前一行的行尾。

函数调用时,如果参数个数很多,或者要传递的表达式写起来很长,那么也会涉及到长语句换行问题,最基本的原则是:尽可能地在参数与参数之间换行,并将逗号保留在上一行行末:

// 在参数与参数之间换行
printf("This function call has many parameters. %d %d %d %d/n", myvar1,
    myvar2, myvar3, myvar4);

在一些必要的情况下,我们为了清晰地列出函数的每一个参数,可以采取类似结构声明的写法:

// 每个参数分行
printf(
    "This function call has many parameters. %d %d %d %d/n",
    myvar1,
    myvar2,
    myvar3,
    myvar4
);

当传入的表达式较为复杂时,这种写法会显得格外地清晰。类似地,在同时声明多个同一类型的变量时,也可以如此书写:

double myvar1,
        myval2,
        myvar3,
        myvar4;

它的主要目的是便于对单个变量进行注释:

char username[MAXN],  // 用户名
      password[MAXN],  //
密码
      desc[MAXN];       //
描述

 

这里提到的都是一些总结出来的比较常见的情况,它们并不是金科玉律,只是一个建议,但却是一个强烈的建议。在遇到本文没有提到的情况时,可以根据实际情况和需要调整缩进。归根结底是为了更加清晰和正确地反映出代码的逻辑结构。

 

你可能感兴趣的:(代码风格)