为什么MSVC C++编译器将一个简单的Hello World扩展为4000行的汇编?[英] Why does the MSVC C++ compiler expand a simple Hello World into 4000 lines of assembly?

本文是小编为大家收集整理的关于为什么MSVC C++编译器将一个简单的Hello World扩展为4000行的汇编?的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

本文来自:IT宝库(https://www.itbaoku.cn)

最近,我正在潜入优化我的C ++代码,因此开始使用编译器资源管理器.由于我主要在Windows上使用Visual Studio开发,因此我使用了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 Compiler Explorer过滤指令和评论后).

MSVC将其爆炸为4000.这些行大多数是单独的函数; MSVC对main本身的定义是7个指令,而对于GCC/Clang的8个指令. (使用gcc/clang使用gnu/linux libstdc++将额外的长度添加到Cout Operator Overload功能,而不仅仅是MSVC(如MSVC)使用其自己的C ++库时的2个指针.)

如果我使用puts之类的东西,则MSVC的总输出相当紧凑,可与GCC/Clang相当,例如这里.

有人可以向我解释一下这里发生了什么,我在做错什么或将我指向正确的方向?

为什么MSVC ASM列表如此肿,以用于使用C ++库的简单功能?

推荐答案

这可能不是一个完整的答案,但我认为我可以解释很多差异.

大部分标准库(例如iostreams)是模板重型代码.我相信Microsoft编译器会生成更多的模板实例化,并依赖链接器来删除不必要的链接器.我认为这是Windows Linker使用的不同策略与大多数POSIX的效果,但这也可能是仅使用不同的标准库实现的结果.

如果您指定/MD,它告诉编译器您打算使用标准库的DLL版本,则生成的代码将从4000多行降至少于500行.我不知道为什么是这样.也许MSVC知道DLL库具有所有必要的模板实例化,而静态库取决于编译器的模板实例化.

您可以通过仅处理C ++异常(使用/EHs)来引起增量改进.默认情况下,编译器将生成处理异步系统异常的代码.尽管您的Hello-World样本未明确使用异常,但标准库的一部分可能会做到.在这一点上,看起来许多其他线路都在设置堆栈放松表并调用破坏者.

MSVC版本中的许多剩余过量似乎是在调用销售器时放松堆栈的存在,因此异常处理模型可能不同.

我认为编译器Explorer过去有一个" clang-cl"选项,但我现在看不到.一般而言,Clang-Cl是一个命令驱动程序,它可以解释CL.EXE选项并调整默认选项,以使Clang生产与Microsoft代码兼容的二进制ABI代码.查看它是否生成像常规案例之类的代码或最终发射代码更像MSVC.

会很有趣.

本文地址:https://www.itbaoku.cn/post/2308947.html

问题描述

Lately I'm diving into optimizing my C++ code and as such started to play around with the compiler explorer. Since i am mainly developing on windows with Visual Studio i used the msvc compiler.

At some point msvc got out of hand. after some fiddling around i could narrow it down to the iostream header, that's supposed to be preferred for I/O (SL.io.3).

#include <iostream>
int main() {
    std::cout << "Hello World!\n";
    return 0;
}

While gcc or clang's total output (main + a static initializer that calls some ios_base init functions) totals about 20 lines of assembly (after the Godbolt compiler explorer filters out directives and comments).
MSVC explodes it into 4000. Most of those lines are separate functions; MSVC's definition of main itself is 7 instructions vs. 8 for gcc/clang. (gcc/clang using GNU/Linux libstdc++ pass an extra length arg to the cout operator overload function, not just 2 pointers like MSVC does when using its own C++ library.)

If i use something like puts instead, MSVC's total output is reasonably compact and comparable to gcc/clang, like here.

Can someone kindly explain to me what is happening here, what im doing wrong or point me in the right direction?

Why are MSVC asm listings so bloated for simple functions using C++ libraries?

推荐答案

This may not be a complete answer, but I think I can explain much of the differences.

Much of the standard library (e.g., iostreams) is template heavy code. I believe the Microsoft compiler generates more template instantiations and relies on the linker to remove unnecessary ones. I think that's an effect of the different strategies the Windows linker uses versus most Posix ones, but it might also be a result of simply using a different standard library implementation.

If you specify /MD, which tells the compiler you intend to use the DLL version of the standard library, the generated code drops from 4000+ lines to fewer than 500 lines. I don't know precisely why that's the case. Perhaps MSVC knows the DLL library has all the necessary template instantiations while the static library depends on template instantiation from the compiler.

You can elicit an incremental improvement by handling only C++ exceptions (with /EHs). By default, the compiler will generate code that handles asynchronous system exceptions as well. And while your hello-world sample doesn't explicitly use exceptions, parts of the standard library probably do. At this point, it looks like a lot of the additional lines are setting up stack unwinding tables and calling destructors.

A lot of the remaining excess in the MSVC version looks like it exists to unwind the stack while calling destructors, so the exception handling model may be different.

I thought Compiler Explorer had a "clang-cl" option in the past but I don't see it now. clang-cl, generally speaking, is a command driver that interprets cl.exe options and adjusts default options to make clang produce code that's binary ABI compatible with Microsoft code. It would be interesting to see if it generates code like regular clang or whether it ends up emitting code more like MSVC.