【发布时间】:2021-12-03 03:20:30
【问题描述】:
在阅读gcc manual 中关于异常处理和编译器标志-fno-exceptions 的部分时,我遇到了以下几行:
异常处理开销可以用 可执行二进制文件,并随底层的功能而变化 操作系统和 C++ 编译器的特定配置。在 最近的硬件与同龄的 GNU 系统软件相结合, 启用异常处理的代码和数据大小开销约为 7%。
我试图通过使用 Ubuntu 20.04 和 gcc 10.3.0 编译一些简单的 C++ 程序(没有异常抛出代码)来重现这种开销,无论是否带有 -fno-exceptions 标志,但无法观察到任何关于大小的差异编译后的二进制可执行文件。
所以我得出的结论是,手册中引用的句子仅指使用 -fno-exceptions 重新编译 libstdc++ 文件时生成的二进制文件,因为在这种情况下,try、catch 和 @ 的每次出现987654328@ 将替换为 if ... else 分支。
我对此并不完全确定,所以这是我的问题:
a) 使用-fno-exceptions 编译的用户代码只会阻止使用关键字try、catch 和throw,并且不会自行生成更小的二进制文件,对吧?
b) 使用 -fno-exceptions 编译的用户代码仍然可以暴露于 libstdc++ 函数抛出的异常,如果这些函数没有使用 -fno-exceptions (重新)编译,对吧?
c) 使用-fexceptions(默认值)编译的用户代码确实会因为生成的帧展开信息而产生更大的二进制文件,但只有在实际使用异常时,对吧?
【问题讨论】:
-
您的“简单 C++ 程序”是否有任何抛出异常的代码?
-
@Frank :不,看我的编辑
-
如果程序没有任何潜在异常抛出代码,那么从可执行文件中剥离所有异常处理代码是一种简单的优化,不会有任何区别。但是,使用 RAII 和不使用 LTO 编译的多 TU 程序肯定会显示出差异,因为编译器无法判断 extern 函数是否可以抛出。
-
这里有一个简单的例子来展示差异:gcc.godbolt.org/z/voGTYcbG6(请注意,LTO 稍后可能仍会在工具链中优化差异)