是的,除以零是未定义的行为,在这种情况下,C 和 C++ 标准都没有强加任何要求。虽然在这种情况下,我认为您至少应该发出诊断信息(见下文)。
在我引用标准之前,我应该注意,虽然这可能是符合行为实施质量是一个不同的问题,但仅仅符合并不等于有用。据我所知,gcc、clang、Visual Studio 和 Intel(根据 tpg2114)团队认为内部编译器错误(ICEs)是应该报告的错误。应该注意的是,当前的 gcc 和 clang 都会针对这种情况产生警告,似乎与提供的标志无关。在两个操作数都是文字/常量的情况下,我们在这里遇到的情况,检测并为此提供诊断似乎相当简单。对于这种情况,clang 会生成以下诊断信息 (see it live):
warning: division by zero is undefined [-Wdivision-by-zero]
int x = 1 / 0 ;
^ ~
来自草案 C11 标准部分 6.5.5 乘法运算符(强调我的):
/ 运算符的结果是第一个操作数除以
第二; [...] 如果值
第二个操作数为零,行为未定义。
所以这是未定义的行为。
C++ 标准部分草案5.6 [expr.mul] 说:
二元 / 运算符产生商 [...] 如果 / 或 % 的第二个操作数为零,则行为未定义 [...]
再次未定义的行为。
C++ 标准草案和 C 标准草案都对未定义行为有类似的定义:
[...]本国际标准没有要求
短语没有要求似乎也允许任何行为,包括nasal demons。两者都有类似的说明,大致如下:
当本国际标准省略任何明确的定义时,可能会出现未定义的行为
行为或程序使用错误构造或错误数据时。 允许的未定义行为
范围从完全忽视情况并导致不可预测的结果,到在翻译或
以环境特征的文件化方式执行程序(有或没有发布
诊断消息),终止翻译或执行(通过发出诊断消息)。
因此,虽然注释不规范,但似乎如果您要在翻译过程中终止,您至少应该发出诊断。 终止这个术语没有定义,所以很难争论这允许什么。我认为我没有见过 clang 和 gcc 在没有诊断的情况下使用 ICE 的情况。
代码一定要执行吗?
如果我们阅读Can code that will never be executed invoke undefined behavior?,我们至少可以看到在 C 的情况下存在争论的空间,即必须执行 1 / 0 以调用未定义的行为。更糟糕的是,在 C++ 案例中,behavior 的定义不存在,因此用于 C 案例的部分分析不能用于 C++ 案例。
似乎如果编译器可以证明代码永远不会被执行,那么我们可以推断它是 as-if 程序没有未定义的行为,但我不认为这是可证明的、合理的行为。
从 C 的角度来看,WG14 defect report 109 进一步阐明了这一点。给出以下代码示例:
int foo()
{
int i;
i = (p1 > p2); /* Must this be "successfully translated"? */
1/0; /* Must this be "successfully translated"? */
return 0;
}
响应包括:
此外,如果给定程序的每一次可能执行都会导致未定义的行为,那么给定程序就不是严格符合的。
一个符合标准的实现不能仅仅因为该程序的某些可能的执行会导致未定义的行为而无法翻译一个严格符合标准的程序。因为 foo 可能永远不会被调用,所以给出的示例必须由符合要求的实现成功翻译。
所以在 C 的情况下,除非可以保证调用未定义行为的代码将被执行,否则编译器必须成功翻译程序。
C++ constexpr 案例
如果 x 是 constexpr 变量:
constexpr int x = 1 / 0 ;
它的格式不正确,gcc 会产生警告,而 clang 会出错 (see it live):
error: constexpr variable 'x' must be initialized by a constant expression
constexpr int x = 1/ 0 ;
^ ~~~~
note: division by zero
constexpr int x = 1/ 0 ;
^
warning: division by zero is undefined [-Wdivision-by-zero]
constexpr int x = 1/ 0 ;
^ ~
请注意 除以零是未定义的。
C++ 标准部分草案5.19 常量表达式 [expr.const] 说:
条件表达式 e 是核心常量表达式,除非 e 的求值遵循
抽象机(1.9),将评估以下表达式之一
并包括以下项目符号:
具有未定义行为的操作 [注意:包括,例如,有符号整数溢出
(第 5 条)、某些指针算术 (5.7)、除以零 (5.6) 或某些移位操作 (5.8)
——尾注];
1 / 0 是 C11 中的常量表达式吗
1 / 0 不是 C11 中的常量表达式,我们可以从 6.6 常量表达式部分看到这一点:
每个常量表达式都应计算为可表示范围内的常量
其类型的值。
虽然,它确实允许:
一个实现可以接受其他形式的常量表达式。
所以1 / 0 在 C 或 C++ 中都不是常量表达式,但这不会改变答案,因为它没有在需要常量表达式的上下文中使用。我怀疑 OP 意味着 1 / 0 可用于常量折叠,因为两个操作数都是文字,这也可以解释崩溃。