前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >代码中%80的非逻辑性代码都可以被它发现

代码中%80的非逻辑性代码都可以被它发现

作者头像
编程珠玑
发布2019-09-03 10:39:14
1.5K0
发布2019-09-03 10:39:14
举报
文章被收录于专栏:编程珠玑

前言

很多代码问题在编译阶段难以发现,只有在运行时才会暴露。即便是在运行时出现问题了,我们可能仍然需要费一番功夫才能最终找到代码的问题。幸运地是,我们可以利用一个工具在编译之前就可以发现这些问题。有了它,基本可以检查出代码中80%的非逻辑性错误。这就是本文要介绍的主角--PC-lint。

PC-lint简介

PC-Lint 是GIMPEL SOFTWARE公司开发的C/C++软件代码静态分析工具。而所谓静态分析是指在不运行代码的方式下,通过词法分析、语法分析、控制流、数据流分析等技术对程序代码进行扫描,验证代码是否满足规范性、安全性、可靠性、可维护性等指标--摘自百科。也就是说,利用PC-lint对我们的代码进行扫描分析,在程序运行之前,就可以发现代码中隐藏的问题。PC-lint除了能够发现诸如未初始化变量、数组越界、内存泄漏等问题,还能提出许多对程序运行效率,空间等方面的改进点。下面就简单介绍一下如何使用PC-lint。

如何使用PC-lint

PC-lint能够在Windows、MS-DOS和OS/2平台上使用,Linux平台可使用FlexeLint、Splint等替代工具。本文介绍仅PC-lint的使用。 注:PC-lint为商用软件。

安装方法不在此介绍,和其他普通软件的安装方式一样。安装完成后,在安装目录下会有lint-nt.exe程序。基本使用方法如下:

代码语言:javascript
复制
lint-nt.exe -u files.lnt #执行之后扫描结果会显示在控制台

其中files.lnt文件中的内容是需要扫描的源代码位置。 例如files.lnt文件内容如下:

代码语言:javascript
复制
D:\pclint\lint\test\test.c
D:\pclint\lint\test\main.c

表明将会对main.c和test.c进行静态检查。 如果源文件比较多,那么将源文件添加带files.lnt中是一件很繁琐的事情,我们可以使用命令来得到我们的files.lnt文件:

代码语言:javascript
复制
dir /S/B *.h *.c > files.lnt 

示例程序

我们直接来看一个例子,看看PC-lint到底有哪些能耐。

示例代码
代码语言:javascript
复制
/*main.c*/
#include <stdio.h>
int main(void)
{

    int a[] = {1,2,3,4,5};
    int sum;
    unsigned int len = sizeof(a)/sizeof(int); 
    int loop;
    for(loop = 0;loop <= len;loop++)
    {
        sum += a[loop];
    }
    if(15 == sum)
    {
        printf("sum = 15\n");
        return 0;
    }   
    else
    {
        printf("sum != 15,sum=%d\n",sum);
        return -1;
    }
}

上面的代码计算数组a的和,并且判断最后和是否等于15。

lnt配置

我们的lnt文件files.lnt配置如下:

代码语言:javascript
复制
-wlib(0)     //对库文件不输出任何错误信息
-iD:\pclint\include  //指定头文件路径
D:\pclint\lint\test\main.c //我们的源代码文件

由于我们的代码包含了stdio.h头文件,因此还需要stdio.h头文件,我把它放在了D:\pclint\include,并在lnt文件中指定了头文件的位置。另外,我们只需要扫描我们自己的源代码,因此使用了-wlib(0)来避免对库文件输出告警信息。

扫描代码

执行命令:

代码语言:javascript
复制
D:\pclint\lint>lint-nt.exe -u .\test\files.lnt>result.txt

这里我们将结果重定向到了result.txt文件中,最后生成的result.txt内容如下:

代码语言:javascript
复制
--- Module:   D:\pclint\lint\test\main.c (C)
                            _
    for(loop = 0;loop <= len;loop++)
D:\pclint\lint\test\main.c  10  Warning 574: Signed-unsigned mix with
    relational
D:\pclint\lint\test\main.c  10  Info 737: Loss of sign in promotion from int to
    unsigned int
                      _
        sum += a[loop];
D:\pclint\lint\test\main.c  12  Warning 530: Symbol 'sum' (line 7) not
    initialized
D:\pclint\lint\test\main.c  7  Info 830: Location cited in prior message
                      _
        sum += a[loop];
D:\pclint\lint\test\main.c  12  Warning 661: Possible access of out-of-bounds
    pointer (1 beyond end of data) by operator '[' [Reference: file
    D:\pclint\lint\test\main.c: lines 8, 10, 12]
D:\pclint\lint\test\main.c  8  Info 831: Reference cited in prior message
D:\pclint\lint\test\main.c  10  Info 831: Reference cited in prior message
D:\pclint\lint\test\main.c  12  Info 831: Reference cited in prior message
                            _
        printf("sum = 15\n");
D:\pclint\lint\test\main.c  16  Warning 534: Ignoring return value of function
    'printf(const char *, ...)' (compare with line 271, file
    D:\pclint\include\stdio.h)
D:\pclint\include\stdio.h  271  Info 830: Location cited in prior message
                                        _
        printf("sum != 15,sum=%d\n",sum);
D:\pclint\lint\test\main.c  21  Warning 534: Ignoring return value of function
    'printf(const char *, ...)' (compare with line 271, file
    D:\pclint\include\stdio.h)
D:\pclint\include\stdio.h  271  Info 830: Location cited in prior message
问题分析

经过扫描之后,发现了代码中的很多问题。我们一一列举:

  • 第10行警告号574,提示有符号数和无符号数混用。我们确实将有符号数loop和无符号数len进行了比较。
  • 第12行警告号530,sum未进行初始化。定义sum变量时,并未进行初始化。
  • 第12行警告号661,提示可能出现数组越界。我们仔细审查代码就会发现,循环对a进行求值时,其循环条件应该是loop < len而不是loop <= len。
  • 第16行,21行提示有返回值没有使用。我们调用printf函数之后,并没有必要使用其返回值,因此我们可以忽略这个警告。
  • 第24行提示警告号527,return语句不可到达。由于前面的if-else结构,使得最后的return语句永远无法执行。
问题修改

前面这段代码是可以编译通过,并且运行的,但是经过PC-lint扫描之后却发现如此之多的问题。我们将发现的问题代码进行修改后如下:

代码语言:javascript
复制
/*main.c*/
#include <stdio.h>
/*lint -e{534}*/
int main(void)
{

    int a[] = {1,2,3,4,5};
    int sum = 0;
    unsigned int len = sizeof(a)/sizeof(int); 
    unsigned int loop;
    for(loop = 0;loop < len;loop++)
    {
        sum += a[loop];
    }
    if(15 == sum)
    {
        printf("sum = 15\n");
        return 0;
    }   
    else
    {
        printf("sum != 15,sum=%d\n",sum);
        return -1;
    }
}

最终PC-lint检查结果如下:

代码语言:javascript
复制
--- Module:   D:\pclint\lint\test\main.c (C)

这里除了修改了我们确定的问题之外,还屏蔽了PC-lint的534号警告,因为我们确认这不会对我们的程序本意造成任何影响,因此使用/*lint -e{534}*/屏蔽了main函数的534号警告。PC-lint屏蔽警告的方法很多,这里不再详述。

总结

通过示例程序可以看出,PC-lint确实能够发现一些隐藏的问题,但实际上它的强大远不止我们前面所看到的那样,利用好PC-lint能够帮助我们在运行程序之前就发现很多难以察觉的问题。本文本意为介绍PC-lint的用途,因此对PC-lint的详细使用并没有做过多介绍,有兴趣的读者可以参考网上的资料进行配置学习,PC-lint所报的警告号都可以通过官方PC-lint错误码查看其含义,帮助修正我们的程序。

问题思考

  • 最原始的代码,运行结果是什么?为什么会出现这样的结果?
  • 如果将sum定义为全局静态变量,并且将循环条件改为loop < len,还会出现同样的结果吗?为什么?
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-10-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 编程珠玑 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • PC-lint简介
  • 如何使用PC-lint
  • 示例程序
    • 示例代码
      • lnt配置
        • 扫描代码
          • 问题分析
            • 问题修改
            • 总结
            • 问题思考
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档