c++ - 编译器如何知道 C++ constexpr 计算不会触发未定义的行为?

标签 c++ language-lawyer undefined-behavior constexpr

C++ 标准 授权 编译器检查 未定义的行为 在 C++ 中 constexpr 计算 .

this talk , Chandler Carruth 表示在检查 UB 时“您将耗尽检测错误的能力”,并且在一般情况下,检测 UB 与 halting problem 相关。 ,所以可以证明 无法决定 .

他说的不是constexpr中的UB,而是自 C++14 起,constexpr 计算与常规程序一样通用 ,所以这仍然适用。

那么当编译器无法确定程序是否为 UB 时,它们会做什么 ?他们是否仍然接受该程序并继续交叉编译?或者他们是否更加保守并拒绝该计划,即使它可能是正确的? (我个人的感觉是他们这样做)

对我来说,这具有实际意义,因为我有一个 constexpr 评估,它使用非平凡的指针算术在 Clang 中编译得很好,但在 GCC 中失败了,而且我很确定这不是 UB。你可以说这是一个 GCC 错误,但如果 UB 是不可判定的,那么所有编译器在这方面都会有错误。

更根本的是,为什么要求无 UB 按标准?有技术原因吗?或者更多的是哲学上的(“如果编译器不能检查,程序员可以触发 UB,就会导致坏事”)?

我认为这与 C++ 的其余部分不一致,因为 C++ 永远不会阻止您用脚射击自己。我希望 GCC 接受我的 constexpr 代码并崩溃,或者如果 UB 则发出垃圾;而不是在不知道它是否是 UB 时不编译。

======
编辑 ======

正如 M.M 和 Nicol Bolas 所指出的,该标准指定了限制(即使在 C++14 中),因此我们永远不会陷入 UB 的停止问题类型。但是,我仍然想知道检查 UB 是否可能太复杂,如果编译器启发式失败,那么他们将它(可能错误地)标记为非 constexpr。

但是我从评论中感觉到这更多是非成熟实现的问题。

最佳答案

In this talk, Chandler Carruth states that "you will run out of the ability to detect errors" when checking for UB, and that in the general case, detecting UB is related to the halting problem, so provably impossible to decide.



停机问题是当您使用一个程序并尝试确定该程序如果要执行时是否肯定会停止。根据定义,停机问题仅将程序视为锁定对象。

不断的评估是...评估。您正在执行程序,而不仅仅是查看源代码。

当您的程序执行未定义的事情时,就会发生未定义的行为。大多数情况下 UB 无法确定是否定义明确或不仅仅是通过检查源代码。考虑这个代码:
void foo(void *ptr)
{
  *reinterpret_cast<int*>(ptr) = 20;
}

那是UB吗?这取决于;如果指向 int 的指针被转入foo ,它将是明确定义的。这段代码是否定义良好,只能由它的执行方式来决定。

持续评估需要执行代码;这就是为什么我们经常将其称为编译时执行。当您执行代码时,可以知道是否是 foo 的特定执行。已传递一个指向实际 int 的指针(忽略 reinterpret_castconstexpr 代码中被禁止的事实)。因此,在评估时,您可以知道 UB 是否正在发生。

So what do compilers do when they cannot decide if a program is UB or not?



这实际上不是可能发生的事情。假设规范是完整的并且没有漏洞,程序的执行是否表现出明确定义的行为只是遵循规范的问题。

您在 GCC 与 Clang 之间遇到的问题不是因为是否可以确定 UB。

More fundamentally, why is UB-free requested by the standard? Is there a technical reason?



假设,我们可以从 C++ 甚至 C 中删除所有未定义的行为。我们可以先验地定义好一切,并从语言中删除任何其评估不能从第一原则确定确定的东西。

标准不会这样做,因为这会很糟糕。它会阻止我们做各种有用的、低级的事情。它会阻止有用的编译器优化。等等。

这些原因都不适用于编译时代码执行。尤其是整个“有用的、低级的东西”部分。对于编译后的代码,生成的代码在一台实际的真机上执行。所以有一个后门与真机对话是有道理的。然而,在编译时,没有真正的机器可以交谈;只有 C++ 定义的抽象机。那么允许UB有什么意义呢?

编译器不会生成机器语言并执行它;常量评估基本上是在编译器中执行脚本语言。与大多数脚本语言一样,您希望它能够安全、正确地进行评估。您希望错误(和 UB 是错误 )被快速捕获并在故障点提供干净的错误消息,而不是在该过程的后期任意死亡。

关于c++ - 编译器如何知道 C++ constexpr 计算不会触发未定义的行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58635074/

相关文章:

c++ - 最大限度地减少 GL 桌面应用程序上的鼠标输入延迟?

c# - 模式匹配条件确保两个属性都不为空,但编译器会发出可能为空引用的警告。为什么?

c++ - 将对象的第一个字段转换为对象的类型真的安全吗?

c++ - 编译器检查未实例化的模板代码是什么?

c++ - 名称查找 : downsides to using unqualified class name inside a class definition/omitting template parameters?

c - 将负 double 转换为 C 标准中定义的 unsigned int 的行为吗? ARM 与 x86 上的不同行为

c - 将变量作为参数进行比较的 printf 的说明

c++ - 在#include 语句中使用垃圾字符没有编译器错误

c++ - OpenCV SVM 分类器图像识别

c++ - 令人困惑的联盟结构