永远不会执行的代码可以调用未定义的行为吗?

时间:2022-10-09 06:14:32

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.

我认为它仍然是未定义的行为,但我找不到任何证据来支持或否定我。

So, any ideas?

那么,有什么想法?

9 个解决方案

#1


71  

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

让我们看看C标准如何定义“行为”和“未定义的行为”。

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).

参考文献是关于isoc 2011标准的N1570草案;我没有意识到在这三种ISO C标准(1990年、1999年和2011年)的任何相关差异。

Section 3.4:

第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.

好吧,这有点含糊,但是我认为一个给定的声明没有“外观”,当然也没有“行动”,除非它实际执行。

Section 3.4.3:

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.

它说“使用”这样的结构。“use”这个词并不是由标准定义的,所以我们又回到了英语中常见的意思。如果一个构造从未被执行过,它就不会被“使用”。

There's a note under that definition:

在这个定义下有一个注解:

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).

注意,可能存在的未定义行为包括:完全忽略无法预测的情况,在翻译或程序执行过程中以环境特征的文档化方式(是否发出诊断消息),终止翻译或执行(发出诊断消息)。

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.

实际上,程序必须能够执行运行时测试以防止调用未定义的行为,并且标准必须允许它们这样做。

Your example was:

你的例子是:

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

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

它从不以0执行除法。一个很常见的习语是:

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

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.

如果y = 0,这个除法当然有未定义的行为,但是如果y = 0,它就不会被执行。行为被定义得很好,同样的原因是您的示例被定义得很好:因为潜在的未定义行为实际上永远不会发生。

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

(除非INT_MIN < -INT_MAX && x == INT_MIN & y = -1(是的,整数除法可以溢出),但这是另一个问题。)

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 is not a constant expression.

1/0不是常数。

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:

常量表达式是一个语法范畴,它可以简化为条件表达式(不包括赋值和逗号表达式)。只有在实际需要一个常量表达式(如case label)的上下文中,生产常量表达式才会出现在语法中。所以,如果你写:

switch (...) {
    case 1/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().

那么1/0是一个常量表达式——它违反了6.6p4中的约束:“每个常量表达式的值都应该在其类型的可表示值范围内。”因此需要进行诊断。但是赋值的右边并不需要一个常量表达式,仅仅需要一个条件表达式,所以常量表达式的约束不适用。编译器可以评估在编译时能够执行的任何表达式,但是只有当行为与在执行期间被评估时相同(或者,在if(0)的上下文中,在执行期间没有进行评估)。

(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.)

(看起来完全像常量表达式的东西不一定是常量表达式,就像在x + y * z中,序列x + y由于出现的上下文而不是添加表达式一样。)

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

也就是N1570第6.6节的脚注我要引用

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

因此,在接下来的初始化中,静态int i = 2 || 1 / 0;表达式是具有值1的有效整数常量表达式。

isn't actually relevant to this question.

与这个问题无关。

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:

最后,有一些事情被定义为导致未定义的行为,它们与执行过程中发生的事情无关。附件J, C标准的第2节(同样参见N1570草稿)列出了导致未定义行为的原因,这些行为是从标准的其他部分收集而来的。一些例子(我不认为这是一个详尽的列表)是:

  • A nonempty source file does not end in a new-line character which is not immediately preceded by a backslash character or ends in a partial preprocessing token or comment
  • 一个非空的源文件不会以换行字符结尾,换行字符前没有反斜杠字符,也不会以部分预处理令牌或注释结尾
  • Token concatenation produces a character sequence matching the syntax of a universal character name
  • 令牌连接产生一个匹配通用字符名称的语法的字符序列。
  • A character not in the basic source character set is encountered in a source file, except in an identifier, a character constant, a string literal, a header name, a comment, or a preprocessing token that is never converted to a token
  • 除了在标识符、字符常量、字符串字面量、头名、注释或从未转换为令牌的预处理标记之外,源文件中还会遇到不在基本源字符集中的字符
  • An identifier, comment, string literal, character constant, or header name contains an invalid multibyte character or does not begin and end in the initial shift state
  • 一个标识符、注释、字符串文字、字符常量或头名称包含一个无效的多字节字符,或者在初始转移状态中不开始和结束。
  • The same identifier has both internal and external linkage in the same translation unit
  • 同一标识符在同一翻译单元中具有内部和外部链接

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.

这些特殊的情况是编译器可以检测到的。我认为他们的行为是没有定义的,因为委员会不希望或不能将相同的行为强加给所有的实现,并且定义一系列允许的行为是不值得的。它们并不属于“永远不会被执行的代码”的范畴,但是为了完整性,我在这里提到它们。

#2


31  

This article discusses this question in section 2.6:

本文将在2.6节中讨论这个问题:

int main(void){
      guard();
      5 / 0;
}

The authors consider that the program is defined when guard() does not terminate. They also find themselves distinguishing notions of “statically undefined” and “dynamically undefined”, e.g.:

作者认为当guard()不终止时,程序就被定义了。他们还发现自己对“静态未定义的”和“动态未定义的”有区别的概念,例如:

The intention behind the standard11 appears to be that, in general, situations are made statically undefined if it is not easy to generate code for them. Only when code can be generated, then the situation can be undefined dynamically.

标准11背后的意图似乎是,通常情况下,如果不容易为它们生成代码,那么这些情况就会被静态地定义为无定义的。只有在可以生成代码时,才能动态地定义这种情况。

11) Private correspondence with committee member.

11)与委员私人通信。

I would recommend looking at the entire article. Taken together, it paints a consistent picture.

我建议阅读整篇文章。总的来说,它描绘了一幅始终如一的画面。

The fact that the authors of the article had to discuss the question with a committee member confirms that the standard is currently fuzzy on the answer to your question.

这篇文章的作者不得不与委员会成员讨论这个问题,这一事实证实了目前标准对于你的问题的答案是模糊的。

#3


5  

In this case the undefined behavior is the result of executing the code. So if the code is not executed, there is no undefined behavior.

在这种情况下,未定义的行为是执行代码的结果。所以如果代码没有执行,就没有未定义的行为。

Non executed code could invoke undefined behavior if the undefined behavior was the result of solely the declaration of the code (e.g. if some case of variable shadowing was undefined).

如果未定义的行为仅仅是代码声明的结果(例如,如果某个变量阴影没有定义),则未执行的代码可以调用未定义的行为。

#4


2  

I'd go with the last paragraph of this answer: https://*.com/a/18384176/694576

我选择这个答案的最后一段:https://*.com/a/18384176/694576

... UB is a runtime issue, not a compiletime issue ...

…UB是一个运行时问题,而不是compiletime问题…

So, no, there is no UB invoked.

没有,没有调用UB。

#5


2  

Only when the standard makes breaking changes and your code suddenly is no longer "never gets executed". But I don't see any logical way in which this can cause 'undefined behaviour'. Its not causing anything.

只有当标准发生改变,你的代码突然不再“永远不会被执行”。但我看不出有什么合乎逻辑的方式可以导致“未定义的行为”。它没有引起任何东西。

#6


2  

On the subject of undefined behaviour it is often hard to separate the formal aspects from the practical ones. This is the definition of undefined behaviour in the 1989 standard (I don't have a more recent version at hand, but I don't expect this to have changed substantially):

在不明确的行为这一主题上,常常很难把形式和实际的区分开来。这是1989年标准中未定义行为的定义(我手头没有更近期的版本,但我不认为这有多大的改变):

1 undefined behavior
  behavior, upon use of a nonportable or erroneous program construct or of
  erroneous data, for which this International Standard imposes no requirements
2 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).

From a formal point of view I'd say your program does invoke undefined behaviour, which means that the standard places no requirement whatsoever on what it will do when run, just because it contains division by zero.

从正式的角度来看,我认为您的程序确实调用了未定义的行为,这意味着标准在运行时不要求它做什么,因为它包含0的除法。

On the other hand, from a practical point of view I'd be surprised to find a compiler that didn't behave as you intuitively expect.

另一方面,从实际的角度来看,我很惊讶地发现编译器没有按照您的直觉所期望的那样运行。

#7


2  

The standard says, as I remember right, it's allowed to do anything from the moment, a rule got broken. Maybe there are some special events with kind of global flavour (but I never heard or read about something like that)... So I would say: No this can't be UB, because as long the behavior is well defined 0 is allways false, so the rule can't get broken on runtime.

标准说,正如我记得的,它被允许做任何事情从那一刻起,规则被打破了。也许有一些特别的事件具有全球风味(但我从未听说或读到过类似事件)……我想说,不,这不能是UB,因为只要行为定义良好,0总是假的,所以规则在运行时不会被破坏。

#8


2  

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

我认为它仍然是未定义的行为,但我找不到任何证据来支持或否定我。

I think the program does not invoke undefined behavior.

我认为程序不会调用未定义的行为。

Defect Report #109 addresses a similar question and says:

缺陷报告#109解决了一个类似的问题,并说:

Furthermore, if every possible execution of a given program would result in undefined behavior, the given program is not strictly conforming. A conforming implementation must not fail to translate a strictly conforming program simply because some possible execution of that program would result in undefined behavior. Because foo might never be called, the example given must be successfully translated by a conforming implementation.

此外,如果给定程序的每一次可能执行都会导致未定义的行为,那么给定的程序就不是严格遵守的。一个符合条件的实现不能仅仅因为程序的某些可能执行会导致未定义的行为而不能转换一个严格符合条件的程序。因为可能永远不会调用foo,所以必须通过符合标准的实现成功地翻译给定的示例。

#9


0  

It depends on how the expression "undefined behavior" is defined, and whether "undefined behavior" of a statement is the same as "undefined behavior" for a program.

它取决于如何定义“未定义行为”的表达式,以及语句的“未定义行为”是否与程序的“未定义行为”相同。

This program looks like C, so a deeper analysis of what the C standard used by the compiler (as some answers did) is appropriate.

这个程序看起来像C,因此对编译器使用的C标准(正如一些答案所做的)进行更深入的分析是合适的。

In absence of a specified standard, the correct answer is "it depends". In some languages, compilers after the first error try to guess what the programmer might mean and still generate some code, according to the compilers guess. In other, more pure languages, once somerthing is undefined, the undefinedness propagate to the whole program.

如果没有特定的标准,正确的答案是“看情况”。在某些语言中,在第一个错误之后,编译器试图猜测程序员的意思,并仍然根据编译器的猜测生成一些代码。在另一种更为纯粹的语言中,一旦某个东西没有定义,那么这种不确定性就会传播到整个程序中。

Other languages have a concept of "bounded errors". For some limited kinds of errors, these languages define how much damage an error can produce. In particular languages with implied garbage collection frequently make a difference whether an error invalidates the typing system or does not.

其他语言有“有界错误”的概念。对于一些有限类型的错误,这些语言定义了一个错误可以产生多大的损害。特别是具有隐含垃圾收集的语言,错误是否会使输入系统失效常常会有所不同。

#1


71  

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

让我们看看C标准如何定义“行为”和“未定义的行为”。

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).

参考文献是关于isoc 2011标准的N1570草案;我没有意识到在这三种ISO C标准(1990年、1999年和2011年)的任何相关差异。

Section 3.4:

第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.

好吧,这有点含糊,但是我认为一个给定的声明没有“外观”,当然也没有“行动”,除非它实际执行。

Section 3.4.3:

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.

它说“使用”这样的结构。“use”这个词并不是由标准定义的,所以我们又回到了英语中常见的意思。如果一个构造从未被执行过,它就不会被“使用”。

There's a note under that definition:

在这个定义下有一个注解:

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).

注意,可能存在的未定义行为包括:完全忽略无法预测的情况,在翻译或程序执行过程中以环境特征的文档化方式(是否发出诊断消息),终止翻译或执行(发出诊断消息)。

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.

实际上,程序必须能够执行运行时测试以防止调用未定义的行为,并且标准必须允许它们这样做。

Your example was:

你的例子是:

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

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

它从不以0执行除法。一个很常见的习语是:

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

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.

如果y = 0,这个除法当然有未定义的行为,但是如果y = 0,它就不会被执行。行为被定义得很好,同样的原因是您的示例被定义得很好:因为潜在的未定义行为实际上永远不会发生。

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

(除非INT_MIN < -INT_MAX && x == INT_MIN & y = -1(是的,整数除法可以溢出),但这是另一个问题。)

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 is not a constant expression.

1/0不是常数。

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:

常量表达式是一个语法范畴,它可以简化为条件表达式(不包括赋值和逗号表达式)。只有在实际需要一个常量表达式(如case label)的上下文中,生产常量表达式才会出现在语法中。所以,如果你写:

switch (...) {
    case 1/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().

那么1/0是一个常量表达式——它违反了6.6p4中的约束:“每个常量表达式的值都应该在其类型的可表示值范围内。”因此需要进行诊断。但是赋值的右边并不需要一个常量表达式,仅仅需要一个条件表达式,所以常量表达式的约束不适用。编译器可以评估在编译时能够执行的任何表达式,但是只有当行为与在执行期间被评估时相同(或者,在if(0)的上下文中,在执行期间没有进行评估)。

(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.)

(看起来完全像常量表达式的东西不一定是常量表达式,就像在x + y * z中,序列x + y由于出现的上下文而不是添加表达式一样。)

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

也就是N1570第6.6节的脚注我要引用

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

因此,在接下来的初始化中,静态int i = 2 || 1 / 0;表达式是具有值1的有效整数常量表达式。

isn't actually relevant to this question.

与这个问题无关。

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:

最后,有一些事情被定义为导致未定义的行为,它们与执行过程中发生的事情无关。附件J, C标准的第2节(同样参见N1570草稿)列出了导致未定义行为的原因,这些行为是从标准的其他部分收集而来的。一些例子(我不认为这是一个详尽的列表)是:

  • A nonempty source file does not end in a new-line character which is not immediately preceded by a backslash character or ends in a partial preprocessing token or comment
  • 一个非空的源文件不会以换行字符结尾,换行字符前没有反斜杠字符,也不会以部分预处理令牌或注释结尾
  • Token concatenation produces a character sequence matching the syntax of a universal character name
  • 令牌连接产生一个匹配通用字符名称的语法的字符序列。
  • A character not in the basic source character set is encountered in a source file, except in an identifier, a character constant, a string literal, a header name, a comment, or a preprocessing token that is never converted to a token
  • 除了在标识符、字符常量、字符串字面量、头名、注释或从未转换为令牌的预处理标记之外,源文件中还会遇到不在基本源字符集中的字符
  • An identifier, comment, string literal, character constant, or header name contains an invalid multibyte character or does not begin and end in the initial shift state
  • 一个标识符、注释、字符串文字、字符常量或头名称包含一个无效的多字节字符,或者在初始转移状态中不开始和结束。
  • The same identifier has both internal and external linkage in the same translation unit
  • 同一标识符在同一翻译单元中具有内部和外部链接

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.

这些特殊的情况是编译器可以检测到的。我认为他们的行为是没有定义的,因为委员会不希望或不能将相同的行为强加给所有的实现,并且定义一系列允许的行为是不值得的。它们并不属于“永远不会被执行的代码”的范畴,但是为了完整性,我在这里提到它们。

#2


31  

This article discusses this question in section 2.6:

本文将在2.6节中讨论这个问题:

int main(void){
      guard();
      5 / 0;
}

The authors consider that the program is defined when guard() does not terminate. They also find themselves distinguishing notions of “statically undefined” and “dynamically undefined”, e.g.:

作者认为当guard()不终止时,程序就被定义了。他们还发现自己对“静态未定义的”和“动态未定义的”有区别的概念,例如:

The intention behind the standard11 appears to be that, in general, situations are made statically undefined if it is not easy to generate code for them. Only when code can be generated, then the situation can be undefined dynamically.

标准11背后的意图似乎是,通常情况下,如果不容易为它们生成代码,那么这些情况就会被静态地定义为无定义的。只有在可以生成代码时,才能动态地定义这种情况。

11) Private correspondence with committee member.

11)与委员私人通信。

I would recommend looking at the entire article. Taken together, it paints a consistent picture.

我建议阅读整篇文章。总的来说,它描绘了一幅始终如一的画面。

The fact that the authors of the article had to discuss the question with a committee member confirms that the standard is currently fuzzy on the answer to your question.

这篇文章的作者不得不与委员会成员讨论这个问题,这一事实证实了目前标准对于你的问题的答案是模糊的。

#3


5  

In this case the undefined behavior is the result of executing the code. So if the code is not executed, there is no undefined behavior.

在这种情况下,未定义的行为是执行代码的结果。所以如果代码没有执行,就没有未定义的行为。

Non executed code could invoke undefined behavior if the undefined behavior was the result of solely the declaration of the code (e.g. if some case of variable shadowing was undefined).

如果未定义的行为仅仅是代码声明的结果(例如,如果某个变量阴影没有定义),则未执行的代码可以调用未定义的行为。

#4


2  

I'd go with the last paragraph of this answer: https://*.com/a/18384176/694576

我选择这个答案的最后一段:https://*.com/a/18384176/694576

... UB is a runtime issue, not a compiletime issue ...

…UB是一个运行时问题,而不是compiletime问题…

So, no, there is no UB invoked.

没有,没有调用UB。

#5


2  

Only when the standard makes breaking changes and your code suddenly is no longer "never gets executed". But I don't see any logical way in which this can cause 'undefined behaviour'. Its not causing anything.

只有当标准发生改变,你的代码突然不再“永远不会被执行”。但我看不出有什么合乎逻辑的方式可以导致“未定义的行为”。它没有引起任何东西。

#6


2  

On the subject of undefined behaviour it is often hard to separate the formal aspects from the practical ones. This is the definition of undefined behaviour in the 1989 standard (I don't have a more recent version at hand, but I don't expect this to have changed substantially):

在不明确的行为这一主题上,常常很难把形式和实际的区分开来。这是1989年标准中未定义行为的定义(我手头没有更近期的版本,但我不认为这有多大的改变):

1 undefined behavior
  behavior, upon use of a nonportable or erroneous program construct or of
  erroneous data, for which this International Standard imposes no requirements
2 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).

From a formal point of view I'd say your program does invoke undefined behaviour, which means that the standard places no requirement whatsoever on what it will do when run, just because it contains division by zero.

从正式的角度来看,我认为您的程序确实调用了未定义的行为,这意味着标准在运行时不要求它做什么,因为它包含0的除法。

On the other hand, from a practical point of view I'd be surprised to find a compiler that didn't behave as you intuitively expect.

另一方面,从实际的角度来看,我很惊讶地发现编译器没有按照您的直觉所期望的那样运行。

#7


2  

The standard says, as I remember right, it's allowed to do anything from the moment, a rule got broken. Maybe there are some special events with kind of global flavour (but I never heard or read about something like that)... So I would say: No this can't be UB, because as long the behavior is well defined 0 is allways false, so the rule can't get broken on runtime.

标准说,正如我记得的,它被允许做任何事情从那一刻起,规则被打破了。也许有一些特别的事件具有全球风味(但我从未听说或读到过类似事件)……我想说,不,这不能是UB,因为只要行为定义良好,0总是假的,所以规则在运行时不会被破坏。

#8


2  

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

我认为它仍然是未定义的行为,但我找不到任何证据来支持或否定我。

I think the program does not invoke undefined behavior.

我认为程序不会调用未定义的行为。

Defect Report #109 addresses a similar question and says:

缺陷报告#109解决了一个类似的问题,并说:

Furthermore, if every possible execution of a given program would result in undefined behavior, the given program is not strictly conforming. A conforming implementation must not fail to translate a strictly conforming program simply because some possible execution of that program would result in undefined behavior. Because foo might never be called, the example given must be successfully translated by a conforming implementation.

此外,如果给定程序的每一次可能执行都会导致未定义的行为,那么给定的程序就不是严格遵守的。一个符合条件的实现不能仅仅因为程序的某些可能执行会导致未定义的行为而不能转换一个严格符合条件的程序。因为可能永远不会调用foo,所以必须通过符合标准的实现成功地翻译给定的示例。

#9


0  

It depends on how the expression "undefined behavior" is defined, and whether "undefined behavior" of a statement is the same as "undefined behavior" for a program.

它取决于如何定义“未定义行为”的表达式,以及语句的“未定义行为”是否与程序的“未定义行为”相同。

This program looks like C, so a deeper analysis of what the C standard used by the compiler (as some answers did) is appropriate.

这个程序看起来像C,因此对编译器使用的C标准(正如一些答案所做的)进行更深入的分析是合适的。

In absence of a specified standard, the correct answer is "it depends". In some languages, compilers after the first error try to guess what the programmer might mean and still generate some code, according to the compilers guess. In other, more pure languages, once somerthing is undefined, the undefinedness propagate to the whole program.

如果没有特定的标准,正确的答案是“看情况”。在某些语言中,在第一个错误之后,编译器试图猜测程序员的意思,并仍然根据编译器的猜测生成一些代码。在另一种更为纯粹的语言中,一旦某个东西没有定义,那么这种不确定性就会传播到整个程序中。

Other languages have a concept of "bounded errors". For some limited kinds of errors, these languages define how much damage an error can produce. In particular languages with implied garbage collection frequently make a difference whether an error invalidates the typing system or does not.

其他语言有“有界错误”的概念。对于一些有限类型的错误,这些语言定义了一个错误可以产生多大的损害。特别是具有隐含垃圾收集的语言,错误是否会使输入系统失效常常会有所不同。