为啥在汇编输出中有这么多 iostream 样板文件?

Posted

技术标签:

【中文标题】为啥在汇编输出中有这么多 iostream 样板文件?【英文标题】:Why so much boilerplate for iostream in assembly output?为什么在汇编输出中有这么多 iostream 样板文件? 【发布时间】:2013-12-26 05:03:10 【问题描述】:

对于以下代码:

int main()


对于g++ -pedantic -Wall -O3 -S -o test.asm test.cpp && cat test.asm,程序集输出干净利落。如果我在顶部使用 gcc -x c ... test c#include <stdio.h>,则输出是 identical 除了标签名称。其实不管是C++ 还是C 模式。 <string><vector><algorithm><ostream> 等其他标头给出相同的结果。

    .file   "test.cpp"
    .section    .text.unlikely,"ax",@progbits
.LCOLDB0:
    .section    .text.startup,"ax",@progbits
.LHOTB0:
    .p2align 4,,15
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    xorl    %eax, %eax
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .section    .text.unlikely
.LCOLDE0:
    .section    .text.startup
.LHOTE0:
    .ident  "GCC: (GNU) 4.9.0 20131223 (experimental)"
    .section    .note.GNU-stack,"",@progbits

但是一旦你添加#include <iostream>,它就会爆炸(省略相同的部分):

    .section    .text.unlikely
.LCOLDE0:
    .section    .text.startup
.LHOTE0:
    .section    .text.unlikely
.LCOLDB1:
    .section    .text.startup
.LHOTB1:
    .p2align 4,,15
    .type   _GLOBAL__sub_I_main, @function
_GLOBAL__sub_I_main:
.LFB1027:
    .cfi_startproc
    subq    $8, %rsp
    .cfi_def_cfa_offset 16
    movl    $_ZStL8__ioinit, %edi
    call    _ZNSt8ios_base4InitC1Ev
    movl    $__dso_handle, %edx
    movl    $_ZStL8__ioinit, %esi
    movl    $_ZNSt8ios_base4InitD1Ev, %edi
    addq    $8, %rsp
    .cfi_def_cfa_offset 8
    jmp __cxa_atexit
    .cfi_endproc
.LFE1027:
    .size   _GLOBAL__sub_I_main, .-_GLOBAL__sub_I_main
    .section    .text.unlikely
.LCOLDE1:
    .section    .text.startup
.LHOTE1:
    .section    .init_array,"aw"
    .align 8
    .quad   _GLOBAL__sub_I_main
    .local  _ZStL8__ioinit
    .comm   _ZStL8__ioinit,1,1
    .hidden __dso_handle
    .ident  "GCC: (GNU) 4.9.0 20131223 (experimental)"
    .section    .note.GNU-stack,"",@progbits

<iostream> 有何特别之处?

可能相关的一句话是:

在静态初始化顺序方面,cout 保证为 不迟于第一次正确构造和初始化 构造了 ios_base::Init 类型的对象,其中包含 算作此类对象的至少一次初始化 具有静态持续时间。

【问题讨论】:

我想知道如果您实际实例化并使用了流,您是否会得到与<ostream> 相同的结果。 你的报价没有回答你的问题吗? @JonathonReinhart 是的,我想是的,但直到我用谷歌搜索后我才知道为什么。 【参考方案1】:

这个MSDN forum link提供了一个代码sn-p:

#include <ostream>
#include <istream>

namespace std

    extern istream cin;
    extern ostream cout;
    ....

    // this is explained below
    static ios_base::Init __foo;    // not its real name
 

相关引述:

现在,前面提到的运行时惩罚:全局对象必须 在您自己的任何代码使用它们之前进行初始化;这是 由标准保证。像任何其他全局对象一样,它们必须是 初始化一次且仅一次。这通常是用一个 像上面那样构造,嵌套类 ios_base::Init 是 正是出于这个原因在标准中指定。

还有standard quote:

根据 §27.3/2:“对象 [std::cin, std::cout, etc.] 是 构建,并且协会是在某个时间之前建立的 到或在第一次类 ios_base::Init 的对象是 构造,并且无论如何在 main 的主体开始之前 执行。”

罪魁祸首确实是ios_base::Init 行,正如cHao 的评论所暗示的那样。因此,如果 msdn 链接正确,则意味着 &lt;iostream&gt; 是 special。

【讨论】:

以上是关于为啥在汇编输出中有这么多 iostream 样板文件?的主要内容,如果未能解决你的问题,请参考以下文章

为啥这段代码输出这么多数字? [复制]

为啥块之间的 GIF 编码/解码中有这么多填充

为啥 C++ 中有这么多字符串类型?

为啥 OPENCV 中有这么多函数使用 InputArray 和 OutputArray 作为函数参数?

为啥创建了这么多 Parquet 文件?我们可以不限制 Parquet 输出文件吗?

为啥 scikit-learn 中的 GridSearchCV 会产生这么多线程