可以code,将永远不会调用不确定的行为被执行? [英] Can code that will never be executed invoke undefined behavior?

查看:122
本文介绍了可以code,将永远不会调用不确定的行为被执行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在code的(零在这个例子中,除)调用未定义的行为将永远不会得到执行,是程序还是不确定的行为?

The code that invokes undefined behavior (in this example, division by zero) will never get executed, is the program still undefined behavior?

int main(void)
{
    int i;
    if(0)
    {
        i = 1/0;
    }
    return 0;
}

我认为它仍然是不确定的行为,但我无法找到在标准的任何证据来支持或拒绝我。

I think it still is undefined behavior, but I can't find any evidence in the standard to support or deny me.

所以,任何想法?

推荐答案

让我们来看看如何在C标准定义条款的行为和未定义的行为。

Let's look at how the C standard defines the terms "behavior" and "undefined behavior".

指的都是ISO C 2011的 N1570草稿标准;我不知道在任何三个公布的ISO C标准(1990年,1999年,和2011年)的有关分歧。

References are to the N1570 draft of the ISO C 2011 standard; I'm not aware of any relevant differences in any of the three published ISO C standards (1990, 1999, and 2011).

第3.4节:

行为结果
  外观或动作

behavior
external appearance or action

好吧,这是一个有点模糊,但我要说的却是一个给定的语句没有亮相,当然也没有行动,除非它实际上执行。

Ok, that's a bit vague, but I'd argue that a given statement has no "appearance", and certainly no "action", unless it's actually executed.

第3.4.3节:

未定义行为结果
  行为,或者在错误数据的使用不可移植的或错误的程序构造,
  对于这本国际标准并没有规定要求

undefined behavior
behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements

它说的在使用的这样的构造。 用是不是由标准定义的话,那么我们退回到普通英文含义。一个结构是不是用,如果它从未执行。

It says "upon use" of such a construct. The word "use" is not defined by the standard, so we fall back to the common English meaning. A construct is not "used" if it's never executed.

有这么定义下一个注意:

There's a note under that definition:

请注意可能的不确定的行为是忽略的情况范围
  完全取消predictable成果,在翻译过程中的行为
  或执行程序中的一个记录方式的特点
  环境(有或没有发出一个诊断消息的),以
  终止翻译或执行(与发行的
  诊断消息)。

NOTE Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).

因此​​,一个允许编译器在编译的时候拒绝你的程序的 的,如果它的行为是不确定的。但是,我的跨pretation的是,它可以这样做的只有的,如果它能够证明程序的每个执行会遇到不确定的行为。这意味着,我想,这:

So a compiler is permitted to reject your program at compile time if its behavior is undefined. But my interpretation of that is that it can do so only if it can prove that every execution of the program will encounter undefined behavior. Which implies, I think, that this:

if (rand() % 2 == 0) {
    i = i / 0;
}

这肯定可以的具有不确定的行为,不能在编译时被拒绝。

which certainly can have undefined behavior, cannot be rejected at compile time.

作为一个实际问题,程序必须能够执行运行时测试,以防范调用未定义行为,标准必须允许他们这样做。

As a practical matter, programs have to be able to perform runtime tests to guard against invoking undefined behavior, and the standard has to permit them to do so.

您的例子是:

if (0) {
    i = 1/0;
}

从未执行0.一个非常常见的成语是分工

which never executes the division by 0. A very common idiom is:

int x, y;
/* set values for x and y */
if (y != 0) {
    x = x / y;
}

当然该部门已未定义行为,如果Ÿ== 0 ,但它永远不会被执行,如果Ÿ== 0 。该行为被明确定义,并为您的例子是明确的同样的原因:因为潜力的未定义行为永远不能真正发生

The division certainly has undefined behavior if y == 0, but it's never executed if y == 0. The behavior is well defined, and for the same reason that your example is well defined: because the potential undefined behavior can never actually happen.

(除非 INT_MIN< -INT_MAX&放大器;&安培; X == INT_MIN和放大器;&安培; Y == -1 (是的,整数除法可能溢出),但这是一个单独的问题。)

(Unless INT_MIN < -INT_MAX && x == INT_MIN && y == -1 (yes, integer division can overflow), but that's a separate issue.)

在评论(自删除),有人指出,编译器可能在编译时间常数前pressions。这是真实的,但在这种情况下不相关,因为在的上下文

In a comment (since deleted), somebody pointed out that the compiler may evaluate constant expressions at compile time. Which is true, but not relevant in this case, because in the context of

i = 1/0;

1/0 不是恒定的前pression

A 恒前pression 的是一个词类减少到的条件-EX pression 的(不包括分配和逗号前pressions )。生产的恒前pression 的出现在实际需要恒定的前pression环境中,如案例标签语法的只有的。所以,如果你写的:

A constant-expression is a syntactic category that reduces to conditional-expression (which excludes assignments and comma expressions). The production constant-expression appears in the grammar only in contexts that actually require a constant expression, such as case labels. So if you write:

switch (...) {
    case 1/0:
    ...
}

然后 1/0 是一个常量前pression - 和一个违反6.6p4约束:每个恒恩pression应评估一个常量,在重新presentable范围
其类型的值。,所以诊断是必要的。但是赋值的右侧不需要的恒前pression 的,仅仅是一个的条件-EX pression 的,所以在不断的前pressions的约束并不适用。编译器能评估任何前pression,它是能够在编译时间,但只有当行为是一样的,如果它在执行过程中进行了评估(或在的背景下,如果(0)的执行过程中评估()。

then 1/0 is a constant expression -- and one that violates the constraint in 6.6p4: "Each constant expression shall evaluate to a constant that is in the range of representable values for its type.", so a diagnostic is required. But the right hand side of an assignment does not require a constant-expression, merely a conditional-expression, so the constraints on constant expressions don't apply. A compiler can evaluate any expression that it's able to at compile time, but only if the behavior is the same as if it were evaluated during execution (or, in the context of if (0), not evaluated during execution().

(东西看起来完全像一个的恒前pression 的并不一定是的恒前pression 的,就像在 X + Y * Z ,序列 X + Y 不是的添加剂-EX pression 因为它出现的背景。)

(Something that looks exactly like a constant-expression is not necessarily a constant-expression, just as, in x + y * z, the sequence x + y is not an additive-expression because of the context in which it appears.)

这意味着N1570 6.6节,我打算举注脚:

Which means the footnote in N1570 section 6.6 that I was going to cite:

因此​​,在下面的初始化,结果,
      静态INT I = 2 || 1/0; 结果
  恩pression是一个有效的整型常量前pression与价值之一。

Thus, in the following initialization,
static int i = 2 || 1 / 0;
the expression is a valid integer constant expression with value one.

不是这个问题实际上是相关的。

isn't actually relevant to this question.

最后,还有一些被定义为导致未定义的行为是不是在执行过程中发生了什么的几件事情。附件J,C标准第2条(再次,请参见 N1570草案)中列出的东西,导致未定义的行为,从标准的其余部分聚集。一些例子(我不声称这是一个详尽的列表),分别是:

Finally, there are a few things that are defined to cause undefined behavior that aren't about what happens during execution. Annex J, section 2 of the C standard (again, see the N1570 draft) lists things that cause undefined behavior, gathered from the rest of the standard. Some examples (I don't claim this is an exhaustive list) are:


      
  • 一个非空源文件中的新行字符,并立即开始不是没有结束美元的反斜杠字符pceded p $或部分结束
      preprocessing令牌或评论

  •   
  • 令牌串联产生匹配通用字符名称语法的字符序列

  •   
  • 在基本源字符集字符不是在源文件中遇到,除了在一个标识符,字符常量,字符串
      文字,标题名称,注释,或preprocessing令牌是
      从来没有转化为令牌

  •   
  • 的标识符,注释,字符串文字,字符常量或头文件名包含无效的多字节字符或不开始
      并最终在初始移位状态

  •   
  • 同样标识符具有在同一个翻译单元的内部和外部连接

  •   

这些特殊的情况下,东西都是一个编译器的可能的检测。我认为他们的行为是不确定的,因为委员会不希望,或不能作出对所有实现相同的行为,并定义了一系列允许的行为只是不值得努力。他们并不真正属于code,将永远不会被执行的范畴,但我在这里提到它们只是为了完整。

These particular cases are things that a compiler could detect. I think their behavior is undefined because the committee didn't want to, or couldn't, impose the same behavior on all implementations, and defining a range of permitted behaviors just wasn't worth the effort. They don't really fall into the category of "code that will never be executed", but I mention them here for completeness.

这篇关于可以code,将永远不会调用不确定的行为被执行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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