在此将以前做C语言程序开发时总结记录的一些稍高级的编程规范记录如下。
1.代码中函数的返回值问题
根据业务需求决定新写的函数是否需要返回值,如果需要返回值就返回需要类型的返回值。并且对返回值要做必要的处理,如果被调用函数有返回值,但是调用函数却没有处理或者不需要处理,这说明被调用函数的返回值没有必要。代码需要重新设计。
常见问题如下:
1)被调用函数执行结果对业务流程有影响时,调用函数却没有处理其返回值。
可能引起的问题包括,可能导致空指针访问、缺少回退处理,如:资源泄露等问题。
2)处理函数的返回值不准确,导致有隐患或问题
主要包括,返回值数据类型被错误转换、返回值比较的目标不是该函数的返回值系列。
2.断言的使用
断言主要用于检查函数的参数值或者某些可能会出现异常的地方调用,使用断言可以在当程序出现异常时,将异常的调用栈打印出来。
通常使用断言的错误包括:
1)在断言中包含非逻辑表达式、对程序运行中可能发生的情况使用断言处理。
2)断言用于对程序运行过程中不应该发生的情况进行检查。
3)条件判断用于对程序中可能发生的情况进行处理。
断言的一般原则:
1)对于同一个文件中的函数,认为是同一个模块的内部函数,相互之间调用时,要求输入参数由调用者保证。模块内部函数建议使用断言来检查参数有效性。
2)对于static或inline函数要求输入参数由调用者来保证,该类函数建议使用断言来检查参数有效性。
3.系统资源的使用
程序中资源的使用一般会犯下面的几种错误:
1)资源的申请释放,没有在同一个层次或者不对称;
要做到资源的申请和释放放在同一个层次上,资源的申请和释放要对称。
2)在成对的系统资源操作之间异常退出;
如果在成对的资源操作之间异常退出,则后边的资源释放不会执行,导致资源泄漏。
3)过早申请资源,导致不必要的异常回退或资源泄露问题;
资源一般在需要使用的时候申请,如果提前申请而没有使用会因为后边的异常导致不必要的回退或者忘记回退会泄露资源。
4)将申请的资源直接赋给间接变量;
正确的做法是先申请资源到局部指针变量,待到确保资源申请成功时再赋值或者挂接资源到数据结构中的间接变量。
4.内存释放问题
内存释放一般会出现如下问题:
1)用错误的函数释放内存资源;
2)释放非法地址的内存、内存重复释放、释放后再重复使用;
3)对于挂接在数据结构上的资源,释放内存时要先从数据结构上摘除;
4)内存资源泄露,没有第一时间释放资源;
5.内存越界问题
内存越界情况主要发生在源数据的空间大于目标空间的大小时,没有做特殊处理。主要表现在如下情况:
1)字符串、内存的拷贝或者清零等操作越界;
2)缓冲区空间太小导致数据溢出;
3)非法参数没有检查导致访问越界;
6.空野指针问题
1)释放全局变量上的资源后没有清零全局变量;
2)释放数据结构上挂接的内存后,没有清零数据结构上挂接的字段;
3)指针释放后重复访问,导致访问空指针;
7.变量未初始化问题
变量要做到定义它时就对其进行初始化,因为不初始化的话它对应的内存里很可能存放任何其他值。
8.代码冗余
这一点主要说的是代码要简洁明了。如果两行代码能解决的问题,就不要写两行以上去解决。如果代码中出现了多层判断逻辑,我们就得考虑分拆封装。
9.编程接口
编写函数时要清楚,一个函数尽量只做一件事情一个功能。函数的命名要和它的功能相对应,这样别人看了我们写的函数名称就可清晰的知道这个函数要实现的功能。
一般在编写函数的时候,我们要清楚下面几点:
1)这个函数要实现什么功能?功能要做到单一,函数的命名要能反映其功能。
2)这个函数的参数有哪些?函数的参数之间是否正交(一个不能推出另一个),参数的作用是什么,函数的参数越少越好。
3)这个函数是否需要返回值?函数的返回值需要外层调用者怎样来处理?返回值可能有哪些情况,每种情况需要外层怎样判断处理。
4)这个函数的代码行数越少越好。
10.资源型接口设计
资源型接口最主要关注的就是资源的申请和释放,所有的问题都是围绕着怎样容易的管理资源出现的。
资源型接口设计经常会出现下面的问题:
1)释放参数携带的资源时规则不一致;
2)复合资源的申请和释放没有封装或申请、释放函数封装不对称;
3)资源创建、获取型函数没有将资源作为返回值,而是作为输出参数;