退出函数的 noreturn 属性是否必要?

Are noreturn attributes on exiting functions necessary?

never-returning 函数的 noreturn 属性是否必要,或者这只是一个(可以说是过早的?——至少对于退出,我无法想象为什么要在那里优化)优化?

有人向我解释说,在

这样的上下文中
void myexit(int s) _Noreturn {
   exit(s);
}
// ...
if (!p) { myexit(1); } 
f(*p);
/// ...

noreturn 防止 !p 分支被优化掉。 但是编译器真的可以优化那个分支吗? 我意识到优化它的理由是:"Undefined behavior can't happen. If p == NULL, dereferencing it is UB, therefore p can never be NULL in this context, therefore the !p branch does not trigger"。但是编译器不能通过假设 myexit 可能是一个不是 return 的函数(即使它没有明确标记为这样)来解决问题吗?

这允许进行多项优化。首先,对于调用本身,这可能允许简化设置,不必保存所有寄存器,可以使用 jmp 指令代替 call 或类似指令。那么调用之后的代码也可以优化,因为没有分支回正常流程。

所以是的,通常 _Noreturn 对编译器来说是一个有价值的信息。

但是直接回答你的问题,不,这是一个属性优化,所以没有必要

Axiom: 标准是关于 C 中明确定义的内容的明确资源。

  • 标准指定assert,因此使用assert是明确定义的。
  • assert 有条件地调用 abort,一个 _Noreturn 函数,因此这是允许的。
  • assert 的每个用法都在函数内部。因此函数可能会也可能不会 return.
  • 标准有这个例子:

    _Noreturn void g (int i) { // causes undefined behavior if i <= 0
        if (i > 0) abort();
    }
    

    因此有条件地 returning 函数不能 _Noreturn。 这意味着:

    • 对于外部定义的函数,编译器必须假定该函数可能不会 return 并且不能自由地优化 if-branch
    • 对于 "internally" 定义的函数,编译器可以检查函数是否确实总是 returns 并优化分支。

在这两种情况下,编译后的程序行为与非优化抽象 C 机器的行为一致,并且遵守 'as-if' 规则。