理解C语言——从小菜到大神的晋级之路(15)——完结篇:C编程风格

本期视频链接:点击这里

有人说过:“程序源代码其实是跟人阅读的,只是恰好机器可以编译而已”。编程初学者常常会有这样一个观念,就是我的程序只要编译通过了,运行没有问题那就万事大吉了。至于代码的编写规不规范,完全就是无关紧要的小事情。如果是处于学习阶段,比如为了完成在学校的C语言课的作业,那么花心思在代码规范上的确没有特别的必要,因为这些代码基本不会进入实用工程,也不会被很多人阅读到。

但是,如果应用到了工程领域,比如在软件/互联网企业的技术研发部门,或者Github等平台上的开源工程,那么编程的规范性将变得无比重要。因为在这些场合,你写的代码将被许多人阅读,并且可能会成为许多人进行后续开发的基础。此时,差劲的代码风格将严重拉低其他开发人员的工作效率。因此,我们推荐从一开始学习便养成一个良好的编程习惯,维持一个合理的代码风格,这样对未来的工作大有裨益。

C语言编程风格的内容相当庞大,这里只挑选一部分相对常用而且比较重要的内容作为参考,主要分为5个部分,包括排版、注释、命名、变量/结构、函数等。

1、排版

程序排版使得代码的结构更加清晰明了,而且有助于理解上下文的逻辑关系。
(1)程序块应根据上下文关系采用缩进风格,缩进的长度根据具体标准规定;
(2)独立的程序块之间、变量说明之后必须加空行;比如:

int fun()
{
     int nVal1 = 0, nVal2 = 5, nSum;

     {
          nSum = nVal1 + nVal2;
     }

     printf("Sum is %d\n", nSum);
}

(3)一条语句占一行,不允许将两条语句写在一行中;
(4)对于存在判断、循环的代码,像if/for/do/while/case/swith/default等部分独占一行,且无论执行部分有多少条语句,都必须使用大括号{ };
(5)包裹代码块的大括号{ }必须另起一行,不要跟随上一行代码的末尾;且大括号也要符合代码缩进规则;

2、注释

注释虽然不影响程序的运行,但仍然是代码的重要组成部分。完善的代码注释对快速理解代码的功能具有重要意义,相反如果代码逻辑复杂且没有注释,或注释不完整、不科学,那么旁人很难理解这段代码究竟是做什么的。需注意一点,别人无法理解的程序即使运行良好,也永远都是垃圾代码。

添加注释需要注意,注释应简洁、有效,有助于提升对代码的理解。所以添加注释应注意不要添加一些完全无意义或者错误的信息。通常,我们认为一套代码按照优劣分为4个等级:
第一等级:不需要注释,通过优秀的代码风格、标识符命名和代码的上下文关系就可以达到高可读性的代码;
第二等级:代码的命名和组织规范、风格稍显不足,但有完善的注释;
第三等级:代码风格和注释都不够完善,但是组织了较为完善的文档在一定程度弥补了这一缺陷;
第四等级:代码风格、注释和文档都不足,这种就属于其他人难以理解的垃圾代码。

函数头部的注释:
在函数头部应添加注释,说明函数的功能、参数、返回值等信息。下面的注释格式比较完善,不一定要局限与此,但建议保留其中的大部分信息:

/*************************************************
  Function: // 函数名称
  Description: // 函数功能、性能等的描述
  Calls: // 被本函数调用的函数清单
  Called By: // 调用本函数的函数清单
  Input: // 输入参数说明,包括每个参数的作
  // 用、取值说明及参数间关系。
  Output: // 对输出参数的说明。
  Return: // 函数返回值的说明
  Others: // 其它说明
*************************************************/

代码中的注释:
语句的注释应在被注释语句的正上方或右方。如果是在上方的话,除非十分必要否则不要再代码和注释之间插入空格。
对于具有物理含义的常量和变量,以及数据结构,除非命名本身是充分注释的,在声明时必须加以注释。
全局变量要有详细的注释,包括对其功能、取值范围、使用的函数以及存取时的注意事项等。
注释与上方的代码用一行空格间隔。
对选择、循环语句应当添加注释,说明分支、循环体的意义。
在程序块结束的大括号右方添加注释,说明匹配的程序块开始位置。
如以下代码:

if (...)
{
     program code
     while (index < MAX_INDEX)
     {
          program code
     } /* end of while (index < MAX_INDEX) */ // 指明该条while语句结束
} /* end of if (...)*/ // 指明是哪条if语句结束

3、标识符命名

标识符命名是代码风格中的重要组成部分,甚至直接决定了代码可读性的高低。最常用的标识符无非就是常量名、变量/结构体名、函数名、宏定义、标签名等。对不同的标识符类型一般适用不同的要求,但有一些基本要求是一致的:标识符的命名必须清晰明了,含义明确,尽量少地使用缩写;严禁使用无意义的单个字母如a, b, i, m, n或者func1, fun等无意义的单词或缩写用于命名;

(1)常量、变量、函数命名:

对于变量名和函数名,通常比较常用的有两种命名法:驼峰命名法和下划线命名法,这两种方法的根本区别在于通过怎样的方式来分隔标识符命名中的逻辑断点。
驼峰命名法:通过大小写字母的变化进行分隔,如:int imgWidth = 0; char *studentName = “Jerry”;
下划线命名法:通过下划线进行分隔,如:double earth_moon_distance;

对于函数名和变量名,一般可以使用不同的命名方法,但是需要注意的是只要选定的命名规范就要从头到尾保持不变。通常,我个人的习惯是,变量名和结构体名使用驼峰命名法,变量名用小写开头,结构体用大写开头;函数名使用下划线命名法,公有API以大写字母开头,私有函数以小写开头并声明为static类型。

另外,对于常量、结构体成员变量、全局变量,还可以参考匈牙利命名法的原则,在变量名前加入前缀c_、m_和g_。

(2)宏定义命名

对于宏定义的命名,一律全部使用大写字母,逻辑断点采用下划线分隔,如
#define MAX_ARRAY_LENGTH 256
对于头文件保护作用的宏定义,则以头文件的文件名命名,逻辑断点和扩展名前的点全部用下划线替代,并且在首位各添加一个下划线,如

//ImageProcessing.h
#ifndef _IMAGE_PROCESSING_H_
#define _IMAGE_PROCESSING_H_

/*code*/

#endif

(3)标签名

通常标签名配合goto语句一起使用。由于goto本来就是比较冷门的语句,标签也不是很常用。如果用到,则全部使用小写字母,并且在结尾加_label,如:

void test()
{
     /*code*/
     goto end_label;
     /*code*/

end_label:
     /*code*/
}

4、变量和结构使用规范

变量和结构的使用是编程中最为频繁的动作,如果能正确规范变量的使用,那么对整体的编程风格的提升大有帮助。
(1)变量定义之后立刻初始化。通常数值型变量定以后可以立刻初始化为0、某个负数或其他无意义的数值,指针变量定义后立刻初始化为NULL。这样在后面使用变量时可以更方便地判断变量是否已经被正确地处理,防止无意中使用了未经初始化的值。
(2)除非特别必要,否则尽量减少全局变量的使用,对于跨文件使用的全局变量更要慎重。全局变量是造成代码之间耦合的重要因素,通常使用全局变量越多,代码就越难以维护。
(3)对于数值完全不应当改变的量,一律定义为常量,防止被误修改。
(4)定义一个结构体的功能应当越具体越好,不应定义一个实现多种功能的结构。另一个体现是,不要定义规模过于庞大的结构,这样不但在运行时浪费系统资源,而且逻辑上难以理解。
(5)除非特别必要,尽量减少变量类型之间的强制转换。因为强制转换实际上也是需要计算机额外操作的,过多的强制转换对系统资源也是一种浪费。
(6)定义结构体时注意优化成员之间的顺序,尽量减少因为字节对齐导致的存储空间浪费。

5、函数使用规范

  • 对于可能出现执行错误(如打开文件失败等)的函数,一律通过返回值返回错误码,且错误码用宏定义预先定义好。
  • 除非专门用来设计输出随机信息的函数,所有的函数都应当是可预测的,即相同的输入永远产生相同的输出。
  • 一个函数只完成一个较小的功能,避免出现一个完成大量不相关功能的超长函数。
  • 严格区分输入和输出参数,对于函数体中不应该改变的参数全部声明为const类型。
  • 在函数正式开始进行处理之前,检查输入参数以及其他用到的外部的有效性。
  • 避免使用过长的参数表,可以把相关的参数封装成一个结构体并以该结构体作为参数。
时间: 2024-08-03 23:04:41

理解C语言——从小菜到大神的晋级之路(15)——完结篇:C编程风格的相关文章

理解C语言——从小菜到大神的晋级之路(14)——C编程常见错误

本期视频:点击这里 1.混淆变量的作用域和生存期 变量的作用域和生存期实际上是两个完全不同的概念. 变量的作用域:可以应用这个变量的范围,强调变量使用的空间范围: 变量的生存期:变量的生命周期,强调变量有效的时间:        这两个概念中,作用域更强调变量可以被引用,而生存期更强调其本身是否存在,这二者实际上并没有必然联系.通常情况下,如果处于某个变量的作用域内,那么这个变量一定还在生存期:但是相反,某个变量已经不在其作用域,并不意味着其生存期已结束.变量的生存期常常远大于其作用域.    

理解C语言——从小菜到大神的晋级之路(1)——引言:C语言的前世今生

第一课的视频链接点这里 C语言是现在应用最为广泛的编程语言之一,也是现在依然流行的编程语言中历史最悠久的一种之一.在目前业界广泛使用的编程语言中,许多 种语言是以C为基础发展而来.在多类大学的工程类专业尤其是信息类专业的教学计划中,C语言也是极为重要的基础课之一. 而对于一名以编译型语言为主要开发工具的程序员来说,熟练掌握C语言的用法和理论也可以对其他编程语言获得更深的理解.因此,在这一系列教程中我们希望可以深入理解C语言的方方面面,为后续理解更高级的技术奠定更好的基础. 1.参考资料 <C程序

理解C语言——从小菜到大神的晋级之路(4)——数据类型、运算符和表达式

本期视频点击这里 一.数据类型         对数据进行处理是程序的基本功能之一,因此对于任何编程语言,数据类型都是重要组成部分之一.C语言中定义了较为完善的数据类型体系用于处理不同类型的数据. (1)标识符         C语言中的标识符可以用作变量名.符号名.函数名.文件名等等功能.标识符可以包含字母.数字和下划线(不能以数字开头).C语言是对大小写敏感的语言,因此组成相同但大小写不同的两个标识符将被当作两个不同的标识符处理.         C语言中的标识符可分为三类: 关键字:C语言

理解C语言——从小菜到大神的晋级之路(6)——函数与调用

        视频观看:点击这里         在前面的程序中,由于程序的功能非常简单,所有的代码都在main()函数中实现.如果程序复杂度增加之后,在main()中实现所有代码将显得非常臃肿且缺乏条理.如果可以将一段大的计算任务分解为若干个小任务则可以有效解决这个问题.另外,分解出来的模块还可以进一步构造和重用,而不用每次都编写同样的代码.因此,绝大部分实际的C程序都是由一个简单的主函数和多个规模不同的子函数构成,而不是全部实现在一个很大的main函数中. 1.函数调用简介        

理解C语言——从小菜到大神的晋级之路(9)——多维数组

本节视频链接:点击这里 1.多维数组的定义和结构         一个数组中可以支持各种数据类型,那么一个数组中的每一个元素同样也可以是一个数组.对于上次提到的一维数组,其每个元素都是一个简单数据类型的对象,其结构如同一个一维的数据排列:对于一个二维数组,它的每一个元素都是一个一维数组,其形式如同一个二维的表格,表格的宽度是其中作为数据元素的一维数组的长度,高度是这样的一维数组的个数.简而言之,二维数组的结构是一个矩阵的形式.         例如,我们声明下面这样的一个二维数组: int nM

理解C语言——从小菜到大神的晋级之路(2)——开发环境的选择和HelloWorld程序

视频观看:点击这里 一.常用系统及IDE简介        常言道,工欲善其事必先利其器.除了少数奇葩之外,大部分人应不会去使用记事本或者Word文档去编程吧?几乎所有编程语言都需要一个高效易用的开发环境,C语言也不例外.那么该如何选择C语言开发的环境呢?一个编程开发环境需要考虑操作系统和编译器两部分.个人PC上常用的操作系统和编译器主要有以下几种: 1.Windows        在PC市场上,Windows操作系统一直占据着超过9成的比例.自从20多年前的Windows 3.x逐渐成熟以来

理解C语言——从小菜到大神的晋级之路(10)——结构体、联合体

本节视频链接:点击这里         上篇中讲述的数组是复合数据类型中最简单的一种,一个数组使用一段连续的内存保存了若干个类型相同的数据元素.由于类型和长度相同,数组的每个元素通过数组下标和指针变量访问.如果我们希望一个结构保存多个不同类型的数据元素,那么数组将无能为力.为了实现这样的功能,C语言提供了结构体和联合体. 1.结构体基本概念 (1)结构体的定义         假设我们需要定义一个图形中的点的概念.在一个使用笛卡尔坐标系表示图像的系统中,点的位置使用两个坐标分量表示,即横坐标x和

理解C语言——从小菜到大神的晋级之路(8)——数组、指针和字符串

       本期视频点击这里        在前面几次我们接触的数据类型都是简单数据类型,使用一个数据个体表示一个元素.C语言中还提供了多种复杂数据类型,其中最简单的一种就是数组.数组这一结构使用内存中一段连续的内存空间保存一组相同类型的变量,这些变量通过数组的下标/索引的不同相互区分.数组与指针有着十分紧密的联系,通常使用数组下标能实现的操作都可以使用指针完成,而且使用指针的程序通常效率更高.但是指针和数组也存在着一些明显的差别,如果误用将导致错误.另外,C语言中还定义了一种极为常用的特殊的

理解C语言——从小菜到大神的晋级之路(3)——C源程序的基本结构与调试方法

    本期视频点击这里        在上一篇中,我们进行了Visual Studio 2013的安装以及第一个demo程序"HelloWorld"的建立.现在我们看一下其中的源代码及相关的C语言基础知识.打开工程,可以通过在源文件标签栏的右键菜单中快速打开源代码的所在目录.HelloWorld的简单代码: #include <stdio.h> int main() { printf ( "Hello World! \n" ); return 0 ;