简体   繁体   English

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

[英]Why doesn't the compiler warn you if there is possible Undefined Behaviour?

I was reading the famous Undefined Behavior can cause time travel post and noticed this part: 我正在阅读着名的Undefined Behavior会导致时间旅行发布并注意到这一部分:

First of all, you might notice the off-by-one error in the loop control. 首先,您可能会注意到循环控件中的逐个错误。 The result is that the function reads one past the end of the table array before giving up. 结果是函数在放弃之前读取一个超过表数组末尾的函数。 A classical compiler wouldn't particularly care. 经典的编译器不会特别在意。 It would just generate the code to read the out-of-bounds array element (despite the fact that doing so is a violation of the language rules), and it would return true if the memory one past the end of the array happened to match. 它只会生成读取越界数组元素的代码(尽管事实上这样做违反了语言规则),如果超过数组末尾的内存碰巧匹配,它将返回true 。

A post-classical compiler, on the other hand, might perform the following analysis: 另一方面,后经典编译器可能会执行以下分析:

The first four times through the loop, the function might return true. 通过循环的前四次,函数可能返回true。

When i is 4, the code performs undefined behavior. 当我是4时,代码执行未定义的行为。 Since undefined behavior lets me do anything I want, I can totally ignore that case and proceed on the assumption that i is never 4. (If the assumption is violated, then something unpredictable happens, but that's okay, because undefined behavior grants me permission to be unpredictable. ) 由于未定义的行为让我可以做任何我想做的事情,我可以完全忽略这种情况并继续假设我从来没有4.(如果假设被违反,那么会发生一些不可预测的事情,但这没关系,因为未定义的行为授予我许可无法预测。

According to this post the (newer) compiler can already act upon Undefined Behavior at compile-time which means that it is perfectly capable to spot Undefined Behavior in some cases. 根据这篇文章,(较新的)编译器已经可以在编译时对未定义的行为起作用,这意味着它在某些情况下完全能够发现未定义的行为。 Instead of letting demons fly out of your nose or spawning dragons by eliminating the UB code or just transforming it because it's allowed to why doesn't the compiler just emit a warning that this is probably not intended? 通过消除UB代码或仅仅改变它来让恶魔飞出你的鼻子或产生龙,而不是让它为什么不允许编译器发出警告,这可能不是故意的?

The work of compiler is to compile the code from high level language to lower level. 编译器的工作是将代码从高级语言编译到较低级别。 If you get a descriptive error or warning message, it is the time to thanks to the compiler that it did extra job for you. 如果您收到描述性错误或警告消息,那么现在是时候感谢编译器为您做了额外的工作。 For getting the required warning, use some static code analysis tool. 要获得所需的警告,请使用一些静态代码分析工具。

And anything not well defined in the spec is undefined, and it is not possible to prepare a comprehensive list of undefined behaviour. 规范中没有明确定义的任何内容都是未定义的,并且不可能准备一个未定义行为的综合列表。 Emitting warning on all such behaviours may not be possible. 对所有此类行为发出警告可能是不可能的。

Practically, in many cases, compilers do warn about undefined behaviours specially with proper warning flags like -W -Wall -Wextra -O2 on gcc. 实际上,在许多情况下,编译器会在gcc上使用正确的警告标志(如-W -Wall -Wextra -O2警告未定义的行为。 (with optimization flags like -O2 compiler would do regress analysis of code and may generate more warning) (使用像-O2编译器这样的优化标志会对代码进行回归分析并产生更多警告)

Compilers becomes better and better in diagnostics. 编译器在诊断方面变得越来越好。 But in principal code analyzes is not the work they have to do. 但在主要代码分析中,并不是他们必须做的工作。 It is only a present to you. 它只是给你的礼物。

So it is common: 所以很常见:

To have more then one compiler for translation and check the warnings and errors ( like in jenkins with gcc and clang). 要有多个编译器进行翻译并检查警告和错误(比如使用gcc和clang的jenkins)。

To have static code analyzes also automated ( like also in jenkins ) 静态代码分析也是自动化的(就像在jenkins中一样)

For example: 例如:

cppcheck main.cpp

Results in: 结果是:

[main.cpp:8]: (error) Array 'table[4]' accessed at index 4, which is out of bounds. [main.cpp:8] :(错误)在索引4处访问的数组'table [4]'超出范围。

There are a lot more tools around, commercial or not. 周围有很多工具,无论是否商业化。 To see also run time effects you can give valgrind with all the tools inside a chance. 要查看运行时效果,您可以为valgrind提供机会中的所有工具。

And yes, a lot more can be done by replacing parts of the standard libs by test tools, eg for memory consumption, stack tracing etc. See efence , duma and others. 是的,通过测试工具替换部分标准库可以完成更多工作,例如内存消耗,堆栈跟踪等。请参阅efenceduma等。

But all that will not find all your errors automatically. 但所有这些都无法自动找到所有错误。

It is a must to have unit tests in place ( eg gtest ) and check against your requirements. 必须进行单元测试(例如gtest )并检查您的要求。 This should be done with coverage analyzes. 这应该通过覆盖率分析来完成。 Without the last you have no idea which code you have really tested and which parts of lines/branches are out of control of your tests. 没有最后一个你不知道你真正测试了哪些代码以及哪些部分的行/分支都无法控制你的测试。

The compiler is only one aspect for getting errors in your code. 编译器只是获取代码错误的一个方面。

Last but not least: A good code peer review is very helpful! 最后但同样重要的是:良好的代码同行评审非常有帮助!

A fundamental problem with trying to produce diagnostics in cases where a compiler is assuming that a program will never receive input that would cause Undefined Behavior, and using that assumption to ignore code that would otherwise affect how that input is processed, is that optimizations are most worth doing when they can result in many different pieces of code being eliminated, but in those scenarios the number of diagnostics that would be produced would be so unmanageable as to make the diagnostics useless. 在编译器假定程序永远不会接收会导致未定义行为的输入并使用该假设忽略可能影响输入处理方式的代码的情况下尝试生成诊断的基本问题是优化最多值得做的是,当它们可以导致许多不同的代码被消除时,但在这些情况下,将产生的诊断数量将是如此难以管理,以致于诊断无用。

Personally I think the right approach would be to have compilers document behavioral constraints in many cases where the Standard would impose no requirements, but some behavioral constraints could be guaranteed very cheaply(*), but then have defined directives to facilitate optimization and indicate programmer intention. 就个人而言,我认为正确的方法是让编制者记录行为约束,在许多情况下标准不会要求,但是一些行为约束可以非常便宜地保证(*),但是后来定义了指令以促进优化并指示程序员的意图。 A static analysis tool could then identify places where eliminating code for places a programmer probably doesn't care about could improve efficiency, and allow a programmer to add a directive to say "Feel free to optimize on the blind assumption that condition xxx will be true", or "Feel free to abnormally terminate the program if condition xxx is false, if not having to handle xxx would save code downstream", or "I need behavior to remain constrained to yyy degree if xxx is false." 然后,静态分析工具可以识别消除程序员可能不关心的地方代码可以提高效率的地方,并允许程序员添加指令说“随意假设条件xxx将为真,可以优化“,或者”如果条件xxx为假,如果不必处理xxx则会在下游保存代码,请随意异常终止程序“,或者”如果xxx为假,我需要行为保持约束到yyy度“。 [the latter directive would eliminate messages about xxx if the static analysis tool is run again]. [如果再次运行静态分析工具,后一指令将消除有关xxx的消息]。

(*)Eg guaranteeing that x+1>y will yield 0 if x==INT_MAX would be expensive, but guaranteeing that the expression will never do anything other than yield one or zero would be cheap; (*)例如,如果x == INT_MAX将是昂贵的,保证x+1>y将产生0,但保证表达式除了产生1或0之外永远不会做任何事情将是便宜的; if either a 1 or 0 would meet requirements, the guarantee would allow a programmer to write code that would be more amenable to optimization than would be otherwise possible). 如果1或0满足要求,则保证将允许程序员编写比其他可能的更优化的代码。

If having xxx not be true would imply that there's a problem that the programmer should know about, a directive suggesting that the compiler could terminate the program if it isn't true could help the programmer found out about it. 如果xxx不是真的意味着程序员应该知道一个问题,那么一个指示编译器可以终止程序的指令如果不是真的可以帮助程序员找到它。 Hyper-modern compiler design, however, could have the opposite effect, by making the compiler short-circuit logic like: 然而,超现代编译器设计可能会产生相反的效果,使编译器的短路逻辑如下:

if (xxx) log_message("xxx was okay at checkpoint #57");

[if xxx not being true would cause UB downstream, a compiler could make the log message call unconditional, thus making it appear as though x was true at that point even though it wasn't]. [如果xxx不为真会导致UB下游,编译器可以使日志消息调用无条件,从而使得在该点看起来好像x是真的,即使它不是]。 Shifting a focus toward more programmer-focused optimization (eg if a program contains many "Feel free to terminate the program if xxx is false") would allow a compiler to achieve the same optimizations in places where the programmer cared enough about speed to supply such directives, but without having the compiler's behavior obscure problems. 将注意力转向更多以程序员为中心的优化(例如,如果程序包含许多“如果xxx为假,则可以随意终止程序”)将允许编译器在程序员关心速度提供足够的优化的地方实现相同的优化指令,但没有编译器的行为模糊问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么编译器不警告unsigned to signed conversion? - Why doesn't the compiler warn about unsigned to signed conversion? 为什么编译器不会在同一个翻译单元中警告ODR违规 - Why doesn't the compiler warn against ODR violations in the same translation unit 将本地引用返回到本地变量时,编译器为什么不警告“返回本地变量或临时地址”? - Why doesn't the compiler warn “returning address of local variable or temporary” when returning a local reference to a local variable? 使用未定义的行为是否未定义编译器的行为? - Is the behaviour of the compiler undefined, with Undefined Behaviour? 为什么clang不对模板中的无效代码发出警告? - Why doesn't clang warn of dead code in templates? 这是编译器优化错误还是未定义的行为? - Is this a compiler optimisation bug, or an undefined behaviour? C ++语法错误,编译器不警告或int v = func(&v)错误。 - Error with C++ syntax, compiler doesn't warn or error for int v = func(&v); 为什么编译器在可能的情况下不使虚拟函数成为非虚函数? - Why doesn't compiler make a virtual function non virtual when it is possible? 为什么我的编译器不喜欢此语句? - Why doesn't my compiler like this statement? 为什么编译器不执行类型转换? - Why doesn't the compiler perform a type conversion?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM