关于代码风格

加入社区有几天了,在社区中我看到有不少正在学习编程的新手。新人们可能苦于各种问题,学习前端还是后端?什么是有效的学习路径?

作为一个半只脚踏入程序员门槛的人,我的视野不够广泛,在技术方面也乏善可陈,可能难以在这些方面提出很好的建议。

但是,看到许多人的代码组织得并不好,作为一个稍微有强迫症的人,我想在代码风格方面给新手们提出一些建议,希望能够帮助到你们。

以下为正文。


在我看来,代码风格可以粗略划分为命名缩进对齐留白注释等部分。

由于缩进和对齐是众所周知的规则,这里就不赘述了。

注释规则较为复杂,好的注释应该能够形成文档,并且有许多工具帮助规范,读者可以自行查阅相关工具的文档。

命名

命名属于老生常谈的内容,常见的命名法有驼峰命名法、帕斯卡命名法、下划线命名法。以下是一个例子:

驼峰命名法 帕斯卡命名法 下划线命名法
myHashSet MyHashSet my_hash_set

插一句建议,帖子的表格编辑十分不方便,没法用 Tab 在单元格之间跳转,并且编辑到最后一个单元格后不能使用 Ctrl+Enter 换行,希望站主改进一下~

编辑过程中又发现一个问题,在列表项中添加代码块,换行时会跳出代码模式,导致只能编辑出一行代码。

另外还有两种命名方法:

  • MY_HASH_SET,常用于命名常量;
  • 匈牙利命名法,目前已不再推荐,但偶尔能见到这种命名法的影子,如全局变量的命名 g_ 前缀的全局变量,g 为 global 的缩写,这种用法是建议的。

目前流行的语言一般混用驼峰命名法和帕斯卡命名法,驼峰命名法一般用来命名变量,帕斯卡命名法一般用来命名类。这些是有明确用途的。

留白

空格留白

这是大多数新手不甚注意的部分,空格留白的目的在于提高代码的可读性,以我搜索到的一个 C 语言实现冒泡排序的算法为例:

# include<stdio.h>
int main(void)
{
    int i, j, t, n;
    int a[100];
    scanf("%d",&n);     // A
    getchar();
    for(i=0;i<n;i++)    // B
    scanf("%d",&a[i]);  // C
    for(i=0;i<n-1;i++)
    {
        for(j=0;j<n-1-i;j++)
        {
            if(a[j]>a[j+1])
            t=a[j];
            a[j]=a[j+1];
            a[j+1]=t;
        }
    }
    for(i=0;i<n;i++)
    printf("%d ",a[i]); // C
    return 0;
}

这段代码或许能跑,但并不美观。如果上千行的代码都是这样组织,那么阅读者可能会晕掉+_+

  • A 处,一般来说代码中逗号后面应该加上一个空格,改为 scanf("%d", &n);,这样读者可以很容易地辨识出逗号前后属于两个不同的参数

  • B 处,问题比较多

    • 语法成分混合在一起,for 的三个部分应该用空格分开,也就是 ; 后面加个空格,改为 for(i=0; i<n; i++)
    • for 和后面的括号之间要加上一个空格,便于识别 for 语句和循环头,改为 for (i=0; i<n; i++)
    • 在二元运算符前后要加上空格,便于识别运算符前后的部分,改为 for (i = 0; i < n; i++)
  • C 和 D 处,缩进错误,作为 for 的循环体,应该再缩进一部分,改为

    for (i = 0; i < n; i++)
        printf("%d ", a[i]);
    

我们着重比较一下最大的循环体修改前后的效果:

// 修改前                     // 修改后
for(i=0;i<n-1;i++)        |  for (i = 0;  i < n - 1; i++)
{                         |  {
    for(j=0;j<n-1-i;j++)  |      for (j = 0; j < n - 1 - i; j++)
    {                     |      {
        if(a[j]>a[j+1])   |          if (a[j] > a[j + 1])
        t=a[j];           |              t = a[j];
        a[j]=a[j+1];      |              a[j] = a[j + 1];
        a[j+1]=t;         |              a[j + 1] = t;
    }                     |      }
}                         |  }

应该能感觉到修改后代码的可读性提高了很多。并且,很容易发现这里的 if 语句后面没有用花括号括起来,是个 bug(这也是代码风格带来的好处之一)。

好了,最后再来回顾一下重点:

  • for 循环头的三个部分要用空格分开

    推广开来,如果 for 的循环头的初始化部分有多个变量,也应分开 for (int i = 0, j = 0; ;)

  • for 等关键词后应加上空格分开,如

    while (1) {
    }
    
  • 二元运算符前后要加上空格,如

    double v = (s + ds) / dt;
    

换行留白

没什么好说的,按照代码逻辑分块即可,不同块之间用空行隔开。

整体修改之后的代码

# include<stdio.h>

int main(void)
{
    int i, j, t, n;
    int a[100];

    scanf("%d", &n);
    getchar();

    for (i = 0; i < n; i++)
        scanf("%d", &a[i]);

    for (i = 0; i < n - 1; i++)
    {
        for (j = 0; j < n - 1 - i; j++)
        {
            if (a[j] > a[j + 1])
            {
                t = a[j];
                a[j] = a[j + 1];
                a[j + 1] = t;
            }
        }
    }

    for (i = 0; i < n; i++)
        printf("%d ", a[i]);

    return 0;
}

除了添加空格外,还添加了空行,main 函数被空行组织为变量声明、输入 n、输入数组、排序、输出、返回语句等多个部分。

有点像文章中的段落,或者句读,看代码时在空行处可以休息一下,不必那么紧张(想一想如果一篇文章通篇只有一段,得有多头疼)


到这里该结束了,目前网上的教程很少涉及到代码风格,但良好的代码风格是所有开发者都应该注意的。

在代码风格方面,也有一些争议的地方,如缩进使用 Tab 还是空格、左花括号是否要换行、变量应该如何命名。而 JavaScript 中也常见到 void main () 这样函数名后带有空格的风格,都各有千秋。

本文不涉及这些争论,重要的是,一个项目的代码风格应该是统一的。如果代码风格良好,但整个团队不同文件之间的风格不一致,也会导致问题。

希望大家都能写出美观、漂亮的代码~

coding-style
185 views
Comments
登录后评论
Sign In
·

我记一下,最近在优化编辑器细节,顺便改了

·

修改后的代码还有一个问题 joy ,我更喜欢这样:

#include <stdio.h>
·

很漂亮,清晰易读

·

我觉得写得很好,确实是这样的,有时候代码可以运行,但是不方便以后查阅,或者是出现问题时候容易定位错误

而且好的代码风格就像一本好书,吸引别人看下去。

·

我有一个问题,就是说只有一行的for循环不用大括号包裹感觉很难受啊,虽然能执行但是感觉就像脱离了原有规范一样的感觉,就像整齐的白polo里面有个人穿了个白半袖,尽管只是少个领子,感觉就很难受

·

哈哈哈,终于看到你发帖了,很不错,很有用 smile 还有个小纠结的点就是,左花括号换行还是不换好呢,那种更规范一点呢?我想在一开始就养成良好的习惯才比较好,省得以后改习惯很难。我一开始也都是统一换新行起左花括号的,后来看到别人在旧的行尾起左花括号好像代码更紧凑,没有那么多空行。新行起左花括号肯定是看着比较工整匀称的,有点像Python那种对齐的风格。

#include <stdio.h>

int main(void) {
    int i, j, t, n;
    int a[100];

    scanf("%d", &n);
    getchar();

    for (i = 0; i < n; i++)
        scanf("%d", &a[i]);

    for (i = 0; i < n - 1; i++) {
        for (j = 0; j < n - 1 - i; j++) {
            if (a[j] > a[j + 1]) {
                t = a[j];
                a[j] = a[j + 1];
                a[j + 1] = t;
            }
        }
    }

    for (i = 0; i < n; i++)
        printf("%d ", a[i]);

    return 0;
}

原本我也无法理解这样的对齐方式的,毕竟看着乱,后来发现,用一个左上直角去看,好像就不乱了,同一层的左右花括号跟关键字刚好成一个直角。

不知道大佬们都都是习惯哪一种写法。