前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >你需要认真对待warning,不然......

你需要认真对待warning,不然......

作者头像
腾讯技术工程官方号
发布2018-01-29 17:40:15
1.5K0
发布2018-01-29 17:40:15
举报
olivialu
olivialu

作者介绍:olivialu,架构平台部质量组员工,测试妹子两年来摸爬滚打、踩坑无数,努力从细微处发现问题、提升测试思路和方法,通过构建测试工具,让每个BUG无所遁形。

前言

编译告警有error和warning之分:编译器确定不允许的就认为是error,然后一些违背原则但是编译器又不确定的就定义为warning,所以说warning是编译器为程序员提供的友善建议和意见。但是有warning大部分时候系统都不会出现明显问题,导致很多同学对warning都抱着“warning is okay”的态度,其实warning里是隐藏了一些问题在的,一旦踩坑,查找问题根源确是一件痛苦的事。

下面就简单分享一些老司机经常遇到的告警案例,说说这些warning表明代码可能出现哪些问题。

案例分享

CASE 1: implicit declaration of function 'foo'

含义:隐式声明了函数

可能存在的问题:coredump

代码示例:

猜猜,编译执行后结果如何呢?

上面的 implicit declaration 是最常见的warning之一,这种问题大多数是因为没有包含相应的头文件。编译器是依据header file里申明的函数原型来对调用进行check的,如果没有函数的申明,那么编译器只会抛出”implicit declaration“的warning,而在Link的时候,只要其他lib里面能够找到这样的函数名,那么根据符号匹配就能Link成功。但是,当你运行的时候,假如调用的函数和函数原型不匹配,就会出现coredump,如上面的case所示。所以正确的做法应该是include其他模块的header file,这样如果调用的时候参数类型和个数不匹配便会发生Compile Error。

CASE 2: passing argument 1 of 'foo' from incompatible pointer type

含义:传参类型和声明不一致

可能存在的问题:功能异常

代码示例:

上面的 incompatible type 又是一常见的warning,这样的问题大多数情况下应该是okay的,因为C会进行隐式转换,但是像上面的case估计就踩到雷区了,可能它的输出就未必是你想要的了因为a,b是char类型占1byte,而foo()的两个pointer都是int *,所以在里面进行调换的时候就会发生覆盖的情况,要想知道结果就自己试试吧。

CASE 3: comparison is always true due to limited range of data type

含义:数据类型的位宽导致表达式永远为真

可能存在的问题:死循环、逻辑错误

代码示例:

上面的warning写的很清楚,但是你如果不看估计也未必能发现你是多么的傻,估计在C的第一章节就会讲到常用的数据类型,然后老师还会强调每一种数据类型的长度,char的取值区间是-128 ~ 127,所以这里的<255永远都是ture,这样就产生了你不预期的死循环。

CASE 4: comparison between signed and unsigned integer expressions

含义:无符号数和有符号数之间比较

可能存在的问题:逻辑错误

代码示例:

上面的代码用g++编译会产生一条“comparison between signed and unsigned integer expressions”的警告,上面的隐式转换往往会给你带来非预期的结果,结果会是 -1 > 1,所以要小心此类告警。

CASE 5: ‘xxx’ has virtual functions but non-virtual destructor

含义:类有虚函数却没有虚析构函数

可能存在的问题:资源泄漏

代码示例:

c++建议有virtual函数时,析构函数最好定义为 public & virtual或者 protected & nonvirtual,以防止资源泄漏。如上面的小例子所示,构造时new了一段空间,但析构时没有释放掉,导致出现了内存泄漏

CASE 6: suggest parentheses around assignment used as truth value

含义:建议加个括号赋值表达式两边

可能存在的问题:逻辑错误

代码示例:

在C语言中,非0即代表TRUE,反之为FALSE。上面的语句会以“= ”前面的值用于最后的判断。但是长期的编程实践告诉我们,人们经常在“=”和“==”的使用上出现手误,所以gcc编译器为此要求我们明确地告诉它是“=”而不是“==”,是故意,而非手误。上面的if语句就少了个“=”号,你发现了吗?

CASE 7: left shift count >= width of type

含义:数据溢出

可能存在的问题:逻辑错误

代码示例:

上面这行代码是有问题的,你发现了吗?x为0,而不是2^32,需要按下面这样写,就不会溢出啦:

CASE 8: statement has no effect

含义:无效语句

可能存在的问题:逻辑错误

代码示例:

这是微云下载功能的一段代码,移位后没有自赋值,会导致4G以上文件无法下载,还好下载时,文件都已经被切割了,不会有大文件,不然上线后又是一个故障。

CASE 9: taking address of temporary

含义:使用临时地址

可能存在的问题:未知行为,高危

代码示例:

上面这段代码是段神奇的代码,gcc 4.1.2 上可以编译通过,但会告警“ taking address of temporary”,执行后的结果是:

可见使用临时地址的输出是不符合预期的,而大部分情况下,这种行为的结果是未知的,所以高版本的gcc会直接error,无法编译通过。

CASE 10: invalid access to non-static data member 'xxx' of NULL object

(perhaps the ‘offsetof’ macro was used incorrectly)

含义:非法访问空对象的非静态成员,可能是错误使用了offsetof宏

可能存在的问题:未知行为

代码示例:

程序中的off_pos是计算变量role在player_t结构中的偏移量的,但offsetof 宏仅限于 standard layout & trival,如a built-in type, pointer, union, struct, array, or class with a trivial constructor。而上述代码中的结构体中的map类型不符合上述约束,所以对其offsetof可能会出现未定义的行为

CASE 11: cannot pass objects of non-POD type ‘xxx’ through ‘...’; call will abort at runtime

含义:传入non-POD参数,运行时系统将会abort

可能存在的问题:coredump,高危

代码示例:

这种告警一旦发现请立即修改,一旦执行到,就会abort。

小结

所以,我们应当认真对待warning,如果你不以为然,可能不小心就掉坑里了,有时候还很难爬上来。养成良好的习惯,清除warning,让build更干净,让compiler更happy。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-01-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 腾讯技术工程官方号 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 小结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档