四时宝库

程序员的知识宝库

非常隐晦的C语言代码BUG,很多高手都看不出来问题在哪里?

前几天安排部门里一位年轻的小伙伴写一个工具给我们内部使用,其中要求他实现一个功能就是输入一个文件名,然后根据输入的文件名字符串查找相关文件。那么这里肯定要入参检测,看看字符串长度有没有问题,于是小伙子噼里啪啦写了类似下面这段代码:

#include<stdio.h>
#include<string.h>

int main()
{
  const char * test_str="test_str";

  if(-1 < strlen(test_str))
    printf("字符串长度正常.\n");
  else
    printf("字符串长度异常.\n");

    return 0;
}

写完了之后当然是编译运行此代码。

于是在ubuntu下使用gcc编译器编译出a.out文件,编译器没有报任何错误或者警告,

接着./a.out开始运行程序。运行结果可以看到程序走的是else分支,报字符串异常。

这时候小伙子开始思考问题,奇怪了,test_str这个字符串不是长度绝对大于0,大于-1的,怎么会这样?好吧,那就在if判断前面加一行打印,看看strlen返回的字符串长度是多大。

添加printf打印长度修改代码如下:

#include<stdio.h>
#include<string.h>

int main()
{
   const char * test_str="test_str";

   printf("str len:%u\n",strlen(test_str));

   if(-1 < strlen(test_str))
        printf("字符串长度正常.\n");
   else
        printf("字符串长度异常.\n");

    return 0;
}

然后重新编译运行修改后代码,可以看到结果如下:

可以看到strlen返回的长度值就是8,没有问题,其值是大于-1的,一切正常。但是任然是走的else分支,也就是if判断条件-1 < strlen(test_str) 结果为False,但是不应该啊,8明明大于-1。

小伙伴想了半天,抓破脑袋也不知道是什么情况?不知道问题原因在哪里。

于是就叫来了我帮忙看看。我告诉他,既然-1 < strlen(test_str) 结果为False,那么肯定是这个比较有问题,我没有直接告诉他答案,还是让他仔细再看看。小伙伴子想了半天还是告诉我不知道。

于是开始了我带着他查找的过程。

我问他,strlen返回是什么类型啊,他去查找了一下告诉我说,是size_t类型。

那具体是什么类型,他告诉我说是unsigend int类型,也就是无符号整形类型。

于是我们他,你现在知道问题在哪里了吗?他想了半天还是回一句,还是不知道哦。

于是我继续问,那请问-1是什么类型,他答到,是signed int,有符号整形。

所以你现在知道问题在哪里了吧?

具体来说,strlen 返回的是 size_t,这是一个无符号整数类型。比较有符号整数和无符号整数的时候,根据C语言隐式类型转换的原理,如果是int型与uint型进行比较,则会将int型数据转换为uint型,则-1变成了 2^32-1 = 4294967295,由于-1 被转换为一个非常大的正整数,这将导致 -1 永远都小于 strlen 返回值,即使 strlen 返回的是0。

是不是这样,下面我们来试一下吧。把strlen前面加个强制类型转换,转成int类型,再看看结果怎么样?

小伙子噼里啪啦代码改成如下:

#include<stdio.h>
#include<string.h>

int main()
{
   const char * test_str="test_str";

   printf("str len:%u\n",strlen(test_str));

   if(-1 < (int)strlen(test_str))
        printf("字符串长度正常.\n");
   else
        printf("字符串长度异常.\n");

    return 0;
}

下面运行修改后代码,可以看到结果如下:

可以看到,“字符串长度”正常出来了,表示if判断结果为真,通过了。

基础不牢,地动山摇。

总结一下,这里问题就是C语言的隐式类型转换,加上关键是这里被比较的数是-1,是负数,强制类型转后之后就变成一个很大的正数。如果你这里-1换成0,绝对没有问题的,强制转换也没有问题,这个跟负数的储存方式有关系了。所以这里这个问题非常隐晦,基础不牢,还是真的不容易看出问题所在。

后续持续更新系列高质量文章,码字不易,觉得写的不错欢迎关注、点赞、收藏以及提问。

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言
    友情链接