C语言代码评审小结

概述
在实际的软件开发项目中,代码评审是一个必不可少的流程。代码评审,也称之为代码复查,是指通过阅读开发人员所写的代码来检查源代码与编码规范的符合性以及代码质量的活动。总的说来,代码评审的好处有以下几点:
第一,发现程序问题,提高代码质量。
第二,理清代码逻辑,开阔编程思路。
第三,促进团队交流,提升开发技能。

代码评审的大体流程是这样的:
第一步,团队负责人(通常是开发经理)提前预定好会议室,并通知参与代码评审的人员,让他们做好准备。
第二步,在评审会上,讲解员大声阅读被评审的代码,评审人员就代码的问题给出自己的看法和意见,记录员再将这些意见记录下来。
第三步,评审结束之后,团队负责人将评审记录以邮件的形式发出来,并督促被评审代码的编写者按照评审意见对代码进行修改。

代码评审小结
最近,我参加了几个C语言代码的评审会,发现了代码中一些共同存在的问题,特总结下来,供相关的开发人员参考。

1.添加、修改、删除代码的时候缺少了注释说明。
在很多开发人员看来,注释是可有可无的东西,只要实现了程序的功能即可。实际上,这种想法是不对的。对于缺少必要注释的代码,在刚编写的时候,还能够知道每行代码的作用,但是当经过了多个版本的演进之后,不要说其他人,就算是作者本人,也未必知道当初自己为何要这么编写代码。当你接手缺少注释而读起来很吃力的代码的时候,有一种想把代码原作者拉过来打一顿的冲动。不管你又没有,反正我是有的。

因此,不管工作有多忙,在编写代码的同时,我们一定要在适当的地方添加适当的注释,这也是对一个合格的编程人员的基本要求。

2.在代码关键分支处缺少了日志信息,不便于分析和排查问题。
很多代码在“return”语句之前或else分支处没有日志信息,这使得跟踪代码流程变得比较困难,在程序出现故障的时候不便于分析和排查问题。

例如,如下代码:

if (var1 > 0)
{
    return;
}
if (var2 > 0)
{
    return;
}
if (var3 > 0)
{
    return;
}

当程序执行到这段代码而返回的时候,我们不知道到底是哪个变量大于了0,这导致我们不知从哪里入手排查问题。

正确的做法是在每个“return”语句之前,都添加详细的日志说明,如下语句所示:

if (var1 > 0)
{
    // 日志说明1
    return;
}
if (var2 > 0)
{
    // 日志说明2
    return;
}
if (var3 > 0)
{
    // 日志说明3
    return;
}

又如,如下代码:

if (var1 > 0)
{
    // 执行操作1
}
else
{
    return;
}
if (var2 > 0)
{
    // 执行操作2
}
else
{
    return;
}
if (var3 > 0)
{
    // 执行操作3
}
else
{
    return;
}

当程序执行到这段代码而返回的时候,我们不知道到底是在哪个else分支返回的。正确的做法同上,要在每个“return”语句之前,都添加详细的日志说明。

3.代码中出现了魔幻数字,不知道它们表达的意思。
例如,如下代码:

if (var1 == 100)
{
    // 执行操作1
}
else if (var1 == 200)
{
    // 执行操作2
}
else if (var1 == 300)
{
    // 执行操作3
}
else
{
    // 执行操作4
}

在看到这段代码的时候,我们不知道代码中的100、200、300表示什么意思,只是感觉头有点晕。这类我们不知道表达什么意思的数字就统称为魔幻数字。

为了消灭魔幻数字,正确的做法是将它们用宏替代,以提高代码的可阅读性和可修改性。将上面的代码修改之后如下所示:

#define   SMALL    100
#define   MEDIUM   200
#define   BIG      300

if (var1 == SMALL)
{
    // 执行操作1
}
else if (var1 == MEDIUM)
{
    // 执行操作2
}
else if (var1 == BIG)
{
    // 执行操作3
}
else
{
    // 执行操作4
}

4.在使用字符串相关操作函数strcpy、memcpy等的时候,没有判断拷贝长度。
在涉及到字符串相关操作的时候,大家一定注意防止操作不当而引起内存越界。如下代码没有判断拷贝长度,就容易引起了内存越界:

char src[100] = {0};
char dest[80] = {0};

strcpy(dest, src);

如上面的代码所示,当src中字符串的长度大于了80的时候,就会出现内存越界的情况,程序就会崩溃。

正确的做法是在执行拷贝操作之前,先判断字符串的长度,同时将strcpy函数替换为strncpy。修改之后的代码如下所示:

char src[100] = {0};
char dest[80] = {0};
int  len      = 0;

if (strlen(src) >= sizeof(dest)-1)
{
    len = sizeof(dest)-1;
}
else
{
    len = strlen(src);
}
strncpy(dest, src, len);

5.if…else语句的判断条件不明确,用多个变量作为多个else if的判断条件。
例如,如下代码所示:

#define   SMALL    100
#define   MEDIUM   200
#define   BIG      300

if (var1 == SMALL)
{
    // 执行操作1
}
else if (var1 == MEDIUM)
{
    // 执行操作2
}
else if (var2 == BIG)
{
    // 执行操作3
}
else if (var3 == BIG)
{
    // 执行操作4
}
else
{
    // 执行操作5
}

在上面的代码中,if…else语句的判断条件中使用了三个不同的变量var1、var2和var3,这导致了代码阅读起来不方便,而且后续对代码的修改也容易出现错误。

正确的做法是同一级的if…else语句的判断条件中要使用相同的变量,修改之后的代码如下所示:

#define   SMALL    100
#define   MEDIUM   200
#define   BIG      300

if (var1 == SMALL)
{
    // 执行操作1
}
else if (var1 == MEDIUM)
{
    // 执行操作2
}
else
{
    if (var2 == BIG)
    {
        // 执行操作3
    }
    else
    {
        if (var3 == BIG)
        {
            // 执行操作4
        }
        else
        {
            // 执行操作5
        }
    }
}

6.定义变量的时候排版不工整。
在编写几乎每一个函数的时候,我们都会定义一些变量,包括整型变量、字符型变量、指针变量、结构体变量等。如果把这些变量放在一起而不注意排版,那么看起来会非常的乱。如下代码所示:

char str1[50] = {0};
int i = 0;
int max = 0;
char str2[500] = {0};
char *pStr = NULL;
TestStruct_T tTestStruct = {0};
int j = 0;
char str3[1000] = {0};

从上面的代码可以看出,将不同的变量混合放在一起,代码看起来很凌乱,严重影响了程序的可阅读性。为此,我们要将同种类型的变量放在一起,利用缩进来让它们对齐,并利用空行来分隔不同类型的变量。修改之后的代码如下所示:

int i   = 0;
int j   = 0;
int max = 0;

char str1[50]   = {0};
char str2[500]  = {0};
char str3[1000] = {0};

char *pStr = NULL;

TestStruct_T tTestStruct = {0};

这样修改之后的代码阅读起来,层次感更好,可阅读性更强。

7.没有判断函数输入参数(尤其是指针变量)的合法性。
在定义函数的过程中,我们很容易忘记对它的输入参数的合法性进行校验,这样也就增大了程序出问题的风险。如下代码所示:

void TestFun(char *pMsg)
{
    char buf[1000] = {0};

    memcpy(buf, pMsg, sizeof(buf)-1);

    // 执行后续流程
}

可以看到,在函数TestFun中,我们直接将pMsg拷贝到buf中,而没有判断其是否为空。如果pMsg为空,那么这个拷贝就会出现问题,程序就会崩溃。

正确的做法是在使用输入指针pMsg之前,先对其合法性进行校验,也就是判断它是否为空。如果为空,那么直接返回,不进行后续处理。修改之后的代码如下:

void TestFun(char *pMsg)
{
    char buf[1000] = {0};

    if (pMsg == NULL)
    {
        printf(“TestFun: pMsgis NULL!\n”);
        return;
    }
    memcpy(buf, pMsg, sizeof(buf)-1);

    // 执行后续流程
}

总结
不管是开发什么样的软件产品,只要需要写代码,那么就离不开代码评审。通过代码评审,我们不仅可以很快发现代码中存在的问题,而且可以发现自己思维的缺陷及在技术上的欠缺,这对提升开发人员本身的素质也是很有好处的。

在代码评审的时候,大家要本着实事求是的态度,不要因为怕伤了和气而不好意思将问题讲出来,更不要由代码问题而转向对开发人员的人身攻击(例如说某人写的代码太烂了)。我们始终要记住大家的共同目标:将产品做好。

时间: 2024-09-22 04:47:36

C语言代码评审小结的相关文章

同行代码评审过程中的实践经验

数百万年前,猿从树上下来,进化出了对生拇指,最终,变成了人类. 我们以类似的眼光来看下强制性代码评审(Code Review):好像是一种能在软件开发这块广阔的领域里将人类从兽里分离出来的东西. 不过,我有时候会从我们的团队成员里听到下面这样的评论: "这个项目的代码评审根本就是浪费时间." "我没有时间做代码评审." "我的项目发布延期了,都是因为我那懦弱的同事还没有做任何评审." "你能相信我的同事竟想让我在代码中改点东西吗?请向他

iOS - CodeReview 代码评审

1.CodeReview Code Review 中文应该译作 "代码审查" 或是 "代码评审",这是一个流程,当开发人员写好代码后,需要让别人来 review 一下他的代码,这是一种有效查找系统缺陷的方法.由此,我们可以审查代码的风格.逻辑.思路 ......,找出问题,以及改进代码,保证软件总体质量和提升开发者自身水平.因为这是代码刚刚出炉的时候,所以,这也是代码重构,代码调整,代码修改的最佳时候.所以,Code Review 是编码实现中最最重要的一个环节.

基于 Rational Team Concert 定制代码评审流程及工具

引言 IBM Rational Team Concert(RTC)是 IBM Rational 面向软件交付技术的下一代协作平台-Jazz 平台上的软件开发环境,它通过集成工作项追踪.源代码控制和可配置的流程管理来实现敏捷开发.其中流程管理是其区别于一般版本管理工具的一个重要功能,它更注重于将对代码的管理融入到整个代码的开发周期和团队协作当中去. 本文基于 RTC 定制了一套代码评审流程.该流程能够帮助 Moderator 管理评审任务,分配评审任务给多个 Reviewer,以及追踪代码评审中发

在Delphi编程中使用C语言代码

Windows下编程的工具有很多,例如VB,Delphi,VC等等.我在这里不想讨论"它们的具体哪个更好一点"这种幼稚的问题.玩过DOS程序设计的人都知道,DOS下很多语言的实质核心还是调用系统提供的汇编中断函数.到了Windows下,它就变成了我们常说的API了.而在Windows下写程序很多时候都是调用API,语言,只不过是一个表达工具而已. 我现在已经参加工作大约有半年左右,我们公司是用Borland公司的Delphi作为主开发工具.本着未偏袒任何一个工具的立场,我说句公道话:D

QQ输入法怎么快捷输入HTML语言代码?

  QQ输入法怎么快捷输入HTML语言代码?          安装好QQ拼音,在输入法状态条点右键----属性设置; QQ输入法 进入高级设置----自定义短语设置; (自定义短语设置前面的勾打上才能启动该功能) QQ输入法 点 添加; 编辑短语 上面的填快捷语,下面填完整语句; 这里我快捷语用"hi",完整的代码是"[hide][/hide]"; QQ输入法 添加完了以后点确定退出设置; QQ输入法 以后用QQ输入法,只要输入"hi",就能出

如何将C语言代码转换为应用程序

有时候我们将让我们的c语言代码保存为一个exe方便,方便使用,实际就是我们俗说的编译   C语言是高级语言,它的语法接近于人类的自然语言,但比自然语言严谨.计算机无法直接将C语言的代码运行,他们并不懂得什么是C语言,实际上,计算机只处理他们的机器语言,所以我们必须为自己找一个翻译,这个翻译可分为2种: 1.编译器 编译器是"文章的译者",它在我们完成创作后将其翻译(实际上是编译)成为机器语言. 2.解释器 解释器是"随声翻译",代码运行的同时它们就开始工作,BASI

交换两个文本内容的C语言代码

这篇文章主要介绍了交换两个文本内容的C语言代码,有需要的朋友可以参考一下 文本存储的位置:   jack.txt位于:    e:jack.txt   retchie.txt位于:     e:retchie.txt   内容:   jack.txt   ->  "Hello! I am Jack."   retchie.txt   ->   "Hello! I am Retchie."   相关代码:     代码如下: #include <st

PHP判断浏览器、判断语言代码分享

 这篇文章主要给大家分享了PHP判断浏览器.判断语言的代码,十分的简单,主要是对服务器预定义变量$_SERVER的获取分析,这里推荐给大家.     PHP编程中经常需要用到一些服务器的一些资料,特把$_SERVER的详细参数整理下,方便以后使用. 判断浏览器类型   代码如下: //判断类型 <?php if(strpos($_SERVER["HTTP_USER_AGENT"],"MSIE 8.0")) echo "Internet Explore

c-VS2013C语言代码无语法错误后调试窗口无显示结果的原因

问题描述 VS2013C语言代码无语法错误后调试窗口无显示结果的原因 include include int main() { int a[2],sum; a[1] = 0; a[0] = 35; sum = a[0] + a[1]; printf("%c", sum); return 0; } 解决方案 %c -> %d 在最后加上 getch() getchar() system("pause") 三者之一 解决方案二: 调试的时候,你设置断点了吗,是不是