警告:吸烟有害健康;程序员:我不关心警告,只关心错误

李肖遥

共 2290字,需浏览 5分钟

 ·

2020-08-24 03:52




关注、星标公众号,直达精彩内容

ID:技术让梦想更伟大

作者:李肖遥


哇,功能终于都实现啦,告一段落了,好开心,,,

  

嗯?我看看你代码?,怎么还有这么多warnning?

  

啊?warnning怕什么呀,又没有错,赶紧提交吧,免得被催得头疼

  

那可不行,两个warnning就可能出现一个错误了


 

来,我通过编译选项将特定警告视为错误,你在编译试试?

嗯?what fuck,怎么还有几十个error了?

  

warnning只是不怎么明显的错误而已,要写出健壮的代码,这些还是要注意的。

  

好滴吧,我继续停留在修改bug的路上了。。。。。。


  
  

视warnning为无物是不是不知道bug怎么来的?

开发中经常会遇到由于各种原因导致的警告,虽然不影响具体的功能,没有出现错误,但是看起来总是让人厌烦,尤其是对于我这种有强迫症的开发者来说。

警告太多会影响对于真正问题的发掘,隐藏我们的视线。

 

凡是出现的警告都是有道理的,搞清楚它。

警告往往是因为会对内存调度等有潜在的威胁,大多数情况下不会出错,而一旦出错,就是灾难性的。

平时我们电脑蓝屏,或者手机卡死,大多数就是这样来的。

所以遇到警告,搞明白它,这是长功夫长能力的最好的时机

把warnning当作error是不是太狠了点?

警告也不一定是错误对吧,当确认它不会造成对运行结果有影响时,才可以去忽略。

有时,警告是因为写得不规范,改一种写法,对自己也是锻炼。

代码提交给测试部的时候,黑盒白盒测试也得过呀,对不对?

但是在开发过程中,不是所有的警告都需要去理会的,毕竟项目进度都摆在那里。

如果说明理由,或者是编译器的警告,暂且略过,没办法了。

warnning < ? < error

有没有哪些warnning确实是error,只是编译器没那么严格?或者有哪些warnning确实没啥事的,不需要花时间去查找了,这样岂不是提高效率?

比“忽略所有warning”要更安全,比开启“视所有warning为error”要宽松精准,所以下面就很关键了!

个人总结的应当视作error的warning

变量没有初始化就使用

函数调用完毕,无法保证用过的栈帧空间后续被如何使用(编译器是否开启优化、栈帧布局结构都有影响),侥幸是不行的。

把int指针和int相互赋值

虽说可以把指针的值(一个地址)当做一个int(其实是unsigned int)来理解,但考虑这种情况:int a=*p被写成int a=p而引发错误。

printf等语句中的格式串和实参类型不匹配

例如

printf("%s%d, szDebugString, ulGwId);

你的ulGwId是一个unsigned long型的,而你为它选择的输出形式却是 “%d”。

把unsigned int和int类型的两个变量比较

有符号数可能在比较之前被转换为无符号数而导致结果错误,这个就不多说了。

函数没有声明就使用

查看关于c编程的书籍可以知道,在函数调用之前,要求先声明,这是为了告诉编译器函数返回值的类型,函数接受的参数的类型和个数。

例如,函数没申明就会出现警告。自己去看结果吧

#include 
 
int main(void)
{
 int c;
 
     c = sun();
 printf("%d",c);
 return 0;
 
}
int  sun()
{
 return 3;
}

指针类型不兼容

例如

#include 
int main()
{
  int array[3][4];
  int **p = array;
}

那么我们改成这样就没问题了。

#include 
int main()
{
  int array[3][4];
  //int **p = array;
 int (*p)[4] = array;
}

函数应该有返回值但是没有return返回值

警告原因:出现这样的警告,有可能是你写了一个

unsigned long FuncA()
{
  if()
  {
    return ulValue;
  }
  if()
  {
    return ulValue;
  }
}

这样的函数,可能在两个if语句中,你都没有进入,这时,退出函数之前,你就根本没有值可以返回。所以要确保在任何情况下该函数都有一个返回值。

使用了影子变量(shadow variable)

内层作用域重新声明/定义了与外层作用域中同名的变量。举一个例子说明shadow变量的危害:

void set_value(int* val) 
{
  double r = 0.0;
  if(isRandom) {
      double r = this->generateRandomNumber();
  }
  *val = r;
}

上述代码运行后,val的值始终是0而不可能被改成随机值。

函数返回局部变量的地址

在C中,正常情况下,我们只能从函数中返回一个值。但在很多情况下,我们需要从函数中返回多个值,此时使用数组或指针能够很好地完成这样的任务。

这里是一个示例。这个程序使用一个整型数组作为参数,并将数组元素的和与积返回给调用函数。代码如下:

#include  
#include  
int* Pool(int array[],int size)  
{  
   int *x;  
   int i=0;  
   int a[2]={0,1};  
   for(i=0;i   {  
      a[0]+=array[i];      //存储数组元素值的和  
      a[1]*=array[i];      //存储数组元素值的积  
   }  
   //将数组的基地址赋值给整型指针  
   x=&a[0];  
   //返回整个数组  
   return x;  
}  
 
int main()  
{  
   int a[]={1,2,3,4};  
   int *c; c = Pool(a,4);  
   printf("Sum = %d\nProduct = %d\n",c[0],c[1]);  
   getch();  
   return 0;  

这样,使用数组和指针从C函数中返回多个值。在很多情况下你会发现这个技巧很有用,但是在C语言中绝不能返回函数内局部变量的地址。

在c语言中,一种典型的错误就是将一个指向局部变量的指针作为函数的返回值。

由于该数组是局部变量,因此在函数返回时其数组空间已经作废了,即指针应用一块无意义的地址空间,所以不会有返回值。

还有很多警告

其实还有很多,我这里不一一列举了,解不完的bug,数的尽的头发。欢迎留言补充!

最后

警告还是很重要的,说到底,我们干的就是要彻底去掉任何有损代码的威胁因素,这样才能写出健壮的代码,那么我们离职后,才能造福后人!

推荐阅读:


嵌入式编程专辑
Linux 学习专辑
C/C++编程专辑

关注微信公众号『技术让梦想更伟大』,后台回复“m”查看更多内容,回复“加群”加入技术交流群。

长按前往图中包含的公众号关注

浏览 12
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报