假设我正在制作一个持久的应用程序,并且不会因任何正常原因而终止(例如用户终止应用程序,例如:HTTP 服务器)。
我用 C++11 标准属性 main
标记 [[noreturn]]
本身,表明它绝不能在不中止或抛出异常的情况下将控制权返回给被调用者。
[[noreturn]] int main(
int const argc,
char const * const[] argv
) { ... }
我首先解析 CLI 参数,然后将提取的数据传递到我的“真实”主函数中,在那里继续进行更多的工作。
另一个函数,我们称之为 realMain
,也标记为 [[noreturn]]
。
在我的代码中,我给 main
函数一个 return 语句到 realMain
中,并立即收到一个关于从 noreturn 函数返回的通用 Clang 警告。
[[noreturn]] int realMain(Data const data) {
...
std::cerr << "Unreachable!" << std::endl;
std::abort();
}
[[noreturn]] int main(...) {
...
auto const parsed_cli_args = parse(argv, argc);
...
return realMain(parsed_cli_args);
}
返回到其他 noreturn 函数是否安全,还是这种未定义的行为?
(和不相关的,任何编译器都可以利用这一点吗?例如,直接将 main
设为 jmp 而不是调用 realMain
?)
答案 0 :(得分:2)
返回到其他 noreturn 函数是否安全,还是这种未定义的行为?
我想知道这里是否有一些语言混乱。
我不确定您的意思是 main()
使用它永远不应该获得的假设返回值返回 realMain()
是否是 UB;或者如果 realMain()
返回 main()
是 UB。
无论如何,基于凯西链接到的 cppreference 示例:
void q [[ noreturn ]] (int i) {
// behavior is undefined if called with an argument <= 0
if (i > 0) {
throw "positive";
}
}
我会理解,仅仅在 return realMain();
中包含 main()
不是 UB。如果 realMain()
真的返回,那只是 UB。到那时,main()
做什么并不重要,因为 realMain()
首先打破了“不返回”的承诺,它已经是 UB。
但由于两者都不应该返回,我不明白你为什么要在任何情况下写 return
,而不是例如只是把对 realMain()
的调用作为 main()
的最后一个语句,没有返回。
答案 1 :(得分:1)
(强调我的)
<块引用>说明
表示函数不返回。
此属性仅适用于在函数声明中声明的函数的名称。 如果具有此属性的函数实际返回,则行为未定义。
如果任何声明指定了该属性,则函数的第一个声明必须指定该属性。如果一个函数在一个翻译单元中用 [[noreturn]] 声明,而在另一个翻译单元中用 [[noreturn]] 声明同一个函数,则程序格式错误;无需诊断。
答案 2 :(得分:1)
这是未定义的行为。按照 C++ 标准中的规定:
<块引用>9.12.9 Noreturn 属性 [dcl.attr.noreturn]
如果函数 f 被调用,而 f 之前是用 noreturn 属性和 f 最终返回,行为是 未定义。
函数是否通过返回另一个 [[noreturn]]
属性函数的结果返回无关紧要。