【发布时间】:2020-05-18 21:22:54
【问题描述】:
最近我正在潜心优化我的 C++ 代码,因此开始使用编译器资源管理器。由于我主要使用 Visual Studio 在 Windows 上进行开发,因此我使用了 msvc 编译器。
在某些时候,msvc 失控了。经过一番摆弄之后,我可以将其缩小到 iostream 标头,这应该是 I/O 的首选(SL.io.3)。
#include <iostream>
int main() {
std::cout << "Hello World!\n";
return 0;
}
虽然 gcc 或 clang 的总输出(main + 一个调用一些ios_base init 函数的静态初始化程序)总共大约 20 行汇编(在 Godbolt 编译器资源管理器过滤掉指令和 cmets 之后)。
MSVC explodes it 进入4000. 这些行中的大多数是单独的函数; MSVC 对main 的定义本身是 7 条指令,而 gcc/clang 是 8 条指令。 (gcc/clang 使用 GNU/Linux libstdc++ 将一个额外长度的 arg 传递给 cout 运算符重载函数,而不仅仅是 MSVC 在使用其自己的 C++ 库时所做的 2 个指针。)
如果我改用 puts 之类的东西,MSVC 的总输出相当紧凑,可以与 gcc/clang 相媲美,例如 here。
有人可以向我解释这里发生了什么,我做错了什么或指出我正确的方向吗?
为什么对于使用 C++ 库的简单函数而言,MSVC asm 列表如此臃肿?
【问题讨论】:
-
你没有做错什么
-
您会发现,在所有编译器的情况下,到链接完成时,该代码无论如何都会在您的可执行文件中结束
-
似乎 MSVC 只包含所有标准库模板实例化 - 例如你可以在那里找到 basic_string(const char*) ctor 等等。生成的程序集列表可能是自包含的,可以由外部汇编器编译。实际的
main函数在main PROC和main ENDP行之间。 -
请注意,编译器资源管理器会减少程序集输出以尝试仅显示相关的内容。考虑到它最初不是为 MSVC 构建的,它有可能摆脱了 GCC/Clang 的东西,而 MSVC 也缺少了同样的东西。另请注意,默认情况下,每个编译器可能包含或多或少的调试内容。例如,我的 Visual Studio 为我提供了 49 KB 的可执行文件用于调试版本,而 11 KB 的可执行文件用于发布版本。
-
@dewaffled:是的,MSVC 发出库模板的定义包括它不调用的模板。但是不,那不是为了让它自成一体。事实上恰恰相反; g++ 确实通过将其 asm 输出提供给单独的汇编器(
as或gas)来工作。被调用但未定义的函数在libstdc++中。 MSVC 的 asm 输出模式包含额外的东西,如果你想将它实际组装成一个目标文件,你必须删除这些东西,你可以链接到一个工作的可执行文件。 AFAIK,如果您实际编译,大部分额外的 asm 都不会作为函数定义出现在.obj中。
标签: c++ visual-studio assembly visual-c++ compiler-explorer