关于未定义行为 [英] On Undefined Behavior

查看:50
本文介绍了关于未定义行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通常,UB 被认为是必须避免的东西,当前的 C 标准本身在附录 J 中列出了很多示例.

Generally, UB is regarded as being something that has to be avoided, and the current C standard itself lists quite a few examples in appendix J.

但是,在某些情况下,除了牺牲可移植性外,我认为利用 UB 没有任何害处.

However, there are cases where I can see no harm in exploiting UB other than sacrificing portability.

考虑以下定义:

int a = INT_MAX + 1;

评估这个表达式会导致 UB.但是,如果我的程序打算在 32 位 CPU 上运行,该 CPU 使用模算术表示二进制补码中的值,我倾向于相信我可以预测结果.

Evaluating this expression leads to UB. However, if my program is intended to run on a, say, 32-bit CPU with modular arithmetic representing values in Two's Complement, I'm inclined to believe that I can predict the outcome.

在我看来,UB 有时只是 C 标准告诉我的方式:我希望你知道你在做什么,因为我们不能对会发生什么做出任何保证."

In my opinion, UB is sometimes just the C standard's way of telling me: "I hope you know what you're doing, because we can't make any guarantees on what will happen."

因此我的问题是:有时依赖于机器的行为是否安全,即使 C 标准认为它会调用 UB,或者无论情况如何,都应该避免使用UB"?

Hence my question: is it safe to sometimes rely on machine-dependent behavior, even if the C standard considers it to invoke UB, or is "UB" really to be avoided, no matter what the circumstances are?

推荐答案

,除非您还保持编译器相同并且您的编译器文档定义了其他情况未定义的行为.

No, unless you're also keeping your compiler the same and your compiler documentation defines the otherwise undefined behavior.

未定义的行为意味着您的编译器可以忽略您的代码,因为任何原因,使您不认为的事情成为现实应该.
有时这是为了优化,有时是因为架构像这样的限制.

Undefined behavior means that your compiler can ignore your code for any reason, making things true that you don't think should be.
Sometimes this is for optimization, and sometimes it's because of architecture restrictions like this.

我建议你阅读这个,它解决了您的确切示例.摘录:

I suggest you read this, which addresses your exact example. An excerpt:

有符号整数溢出:

如果对 int 类型(例如)的算术溢出,则结果未定义.一个例子是 INT_MAX + 1 不保证是 INT_MIN.此行为可启用某些对某些代码很重要的优化类别.

If arithmetic on an int type (for example) overflows, the result is undefined. One example is that INT_MAX + 1 is not guaranteed to be INT_MIN. This behavior enables certain classes of optimizations that are important for some code.

例如,知道 INT_MAX + 1 未定义允许优化 X + 1 >Xtrue.知道乘法不能"溢出(因为这样做将是未定义的)允许将 X * 2/2 优化为 X.虽然这些看起来微不足道,但这些东西通常通过内联和宏扩展暴露出来.这允许的一个更重要的优化是 <= 像这样的循环:

For example, knowing that INT_MAX + 1 is undefined allows optimizing X + 1 > X to true. Knowing the multiplication "cannot" overflow (because doing so would be undefined) allows optimizing X * 2 / 2 to X. While these may seem trivial, these sorts of things are commonly exposed by inlining and macro expansion. A more important optimization that this allows is for <= loops like this:

for (i = 0; i <= N; ++i) { ... }

在这个循环中,如果 i 在溢出时未定义,编译器可以假设循环将精确迭代 N + 1 次,这允许广泛的循环优化另一方面,如果变量被定义为在溢出时环绕,那么编译器必须假设循环可能是无限的(如果 NINT_MAX) - 然后禁用这些重要的循环优化.这尤其会影响 64 位平台,因为很多代码使用 int 作为归纳变量.

In this loop, the compiler can assume that the loop will iterate exactly N + 1 times if i is undefined on overflow, which allows a broad range of loop optimizations to kick in. On the other hand, if the variable is defined to wrap around on overflow, then the compiler must assume that the loop is possibly infinite (which happens if N is INT_MAX) - which then disables these important loop optimizations. This particularly affects 64-bit platforms since so much code uses int as induction variables.

这篇关于关于未定义行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆