首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如果存在可能的未定义行为,编译器为什么不警告您?

如果存在可能的未定义行为,编译器为什么不警告您?
EN

Stack Overflow用户
提问于 2016-06-21 10:35:54
回答 3查看 1K关注 0票数 4

我读了著名的未定义的行为会导致时间旅行。帖子,注意到这部分:

首先,您可能会注意到循环控制中的一个错误.结果是,函数在放弃之前读取表数组结束后的一个。一个经典的编译器不会特别在意。它只会生成代码来读取超出范围的数组元素(尽管这样做违反了语言规则),如果数组结束后的内存恰好匹配,它将返回true。 另一方面,一个后古典编译器可能执行以下分析: 在循环的前四次,函数可能返回true。 在我4岁时,代码执行未定义的行为。由于未定义的行为允许我做任何我想做的事情,所以我可以完全忽略这种情况,并假设我从未4岁。(如果这个假设被违反了,那么会发生一些不可预测的事情,但没关系,因为未定义的行为授予我不可预测的权限。)

根据这篇文章,(较新的)编译器已经可以在编译时对未定义的行为进行操作,这意味着在某些情况下它完全能够识别未定义的行为。而不是让恶魔飞出你的鼻子或产卵龙,通过消除UB代码或只是转换它,因为它是允许的,为什么编译器不只是发出警告,这可能不是故意的?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-06-21 10:42:12

编译器的工作是将代码从高级语言编译到低级语言。如果您收到描述性错误或警告消息,则是时候感谢编译器为您做了额外的工作。要获得所需的警告,请使用一些静态代码分析工具。

而在规范中没有明确定义的任何内容都是未定义的,因此不可能为未定义的行为准备一个全面的列表。对所有这些行为发出警告可能是不可能的。

实际上,在许多情况下,编译器会特别使用适当的警告标志(如gcc上的-W -Wall -Wextra -O2 )来警告未定义的行为。(使用像-O2编译器这样的优化标志可以对代码进行回归分析,并可能产生更多的警告)

票数 6
EN

Stack Overflow用户

发布于 2016-06-21 11:17:24

编译器在诊断方面变得越来越好。但在主代码中,分析并不是他们必须做的工作。这只是给你的礼物。

因此,这是很常见的:

有一个以上的编译器进行翻译和检查警告和错误(如在jenkins与gcc和clang)。

让静态代码分析也是自动化的(也是在jenkins中)

例如:

代码语言:javascript
复制
cppcheck main.cpp

在以下方面的成果:

main.cpp:8:(错误)数组'table4‘在索引4处访问,这是超出界限的。

这里有更多的工具,无论是商业的还是非商业的。要查看运行时效果,您可以给valgrind一个机会,所有的工具都在里面。

是的,通过用测试工具替换部分标准库可以完成更多的工作,例如内存消耗、堆栈跟踪等。请参见efenceduma和其他工具。

但所有这些都不会自动发现你所有的错误。

必须设置单元测试(例如,gtest )并根据您的需求进行检查。这应该通过覆盖率分析来完成。没有最后的代码,您就不知道您真正测试了哪些代码,以及哪些部分的行/分支无法控制您的测试。

编译器只是获取代码中错误的一个方面。

最后但并非最不重要的一点:一个好的代码同行评审非常有用!

票数 2
EN

Stack Overflow用户

发布于 2016-06-21 16:55:57

在编译器假设程序永远不会接收会导致未定义行为的输入的情况下,尝试生成诊断信息的一个根本问题是,使用这种假设忽略否则会影响输入的处理方式的代码,最值得进行的是,当它们可能导致许多不同的代码被消除时,优化是最值得做的,但是在这些场景中,产生的诊断信息的数量将是无法管理的,以致于使诊断变得无用。

就我个人而言,我认为正确的方法是让编译器记录行为约束--在许多情况下,标准将不强加任何要求,但是一些行为约束可以非常便宜地得到保证(*),但随后定义了一些指令,以方便优化并表明程序员的意图。然后,静态分析工具可以确定程序员可能不关心的地方删除代码可以提高效率,并允许程序员添加一条指令,说明“在条件xxx为真的盲目假设下可以随意优化”,或者“如果条件xxx是假的,可以随意终止程序,如果不必处理xxx会将代码保存在下游”,或者“如果xxx是假的,我需要保持约束到yyy的程度”。如果再次运行静态分析工具,后一个指令将消除有关xxx的消息。

(*)例如,如果x+1>y价格昂贵,则保证x==INT_MAX将产生0,但保证表达式除了产生1或0之外,不会做任何其他事情;如果1或0满足要求,则保证允许程序员编写比其他情况下更易于优化的代码)。

如果xxx不是真,就意味着程序员应该知道有一个问题,如果不是真的,建议编译器可以终止程序的指令可以帮助程序员发现这个问题。然而,超现代的编译器设计可能会产生相反的效果,方法是使编译器短路逻辑如下:

代码语言:javascript
复制
if (xxx) log_message("xxx was okay at checkpoint #57");

如果xxx不为真会导致UB下游,编译器可以使日志消息调用是无条件的,从而使它看起来好像在那个时候是正确的,即使不是这样。将焦点转移到更多以程序员为中心的优化(例如,如果一个程序包含许多“如果xxx是假的话可以随意终止程序”),将允许编译器在程序员非常关心提供这些指令的速度的地方实现同样的优化,但不会出现编译器的行为模糊的问题。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37942101

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档