【问题标题】:Include of iostream leads to different binary包含 iostream 会导致不同的二进制文件
【发布时间】:2019-02-04 08:22:53
【问题描述】:

编译如下代码

int main() {
    return 0;
}

给出程序集

main:
        xorl    %eax, %eax
        ret

https://gcc.godbolt.org/z/oQvRDd

如果现在包含iostream

#include <iostream>   
int main() {
    return 0;
}

此程序集已创建。

main:
        xorl    %eax, %eax
        ret
_GLOBAL__sub_I_main:
        subq    $8, %rsp
        movl    $_ZStL8__ioinit, %edi
        call    std::ios_base::Init::Init() [complete object constructor]
        movl    $__dso_handle, %edx
        movl    $_ZStL8__ioinit, %esi
        movl    $_ZNSt8ios_base4InitD1Ev, %edi
        addq    $8, %rsp
        jmp     __cxa_atexit

完全优化已开启 (-O3)。 https://gcc.godbolt.org/z/EtrEX8

谁能解释一下,为什么包含未使用的标头会更改二进制文件。什么是_GLOBAL__sub_I_main:

【问题讨论】:

  • C++ 设计理念 你不使用什么,你不花钱 (Foundations of C++, p. 4) 是一个崇高的目标,但是在某些情况下它没有实现。有很多东西可以使 C++ 二进制文件膨胀却毫无用处,而您偶然发现了其中之一。请注意,语言本身并不强制要求它们;这些是优化它们的工具的失败。
  • @MatthieuM。 - 公平地说,这可以称为programming error。有点像制作一个不必要的虚拟功能。目标可以更好地表达为“你不为你不要求的东西付费”。程序员需要知道他们要求什么。
  • @StoryTeller:我不同意。如果优化器删除了对cout 的任何调用实例,因为它证明分支从未被采用;你仍然会得到那些无用的剩菜。如果你改用printf,那么它将被完全消除。

标签: c++ assembly iostream


【解决方案1】:

包含&lt;iostream&gt; 的每个翻译单元都包含ios_base::Init 对象的副本:

static ios_base::Init __ioinit;

此对象用于初始化标准流(std::cout 及其朋友)。此方法称为Schwarz Counter,它确保标准流在第一次使用之前始终被初始化(前提是已包含iostream 标头)。

该函数_GLOBAL__sub_I_main 是编译器为每个翻译单元生成的代码,它调用该翻译单元中全局对象的构造函数,并安排在退出时调用相应的析构函数调用。此代码在调用 main 之前由 C++ 标准库启动代码调用。

【讨论】:

  • 初始化,并(也许更重要的是)在正常终止之前刷新它们。
  • 有趣的是,__ioinit 本身没有分配存储空间。同时我想知道为什么构造函数不在标记的comdat中。这段代码真的在每个使用iostream 的翻译单元中重复吗?看起来效率真的很低。
  • @fuz _ZStL8__ioinit__ioinit 的存储空间。
  • @fuz - C++17的内联变量定义可以。
  • 这就是为什么在不需要引用 cin、cout、cerr、wcin、wcout 和wcerr.
【解决方案2】:

包含iostream 标头具有添加静态std::ios_base::Init 对象定义的效果。这个静态对象的构造函数初始化标准流对象std::coutstd::cerr等等。

这样做的原因是为了避免静态初始化顺序惨败。它确保跨翻译单元正确初始化流对象。

【讨论】:

  • 换句话说,链接时优化也许能够忽略这一点,对吧?
  • @LightnessRacesinOrbit - 理论上和希望。
  • 即使使用链接时优化,我认为编译器也没有足够的信息来理解 __ioinit 在不引用任何标准流的翻译单元中是多余的。跨度>
猜你喜欢
  • 1970-01-01
  • 2018-02-22
  • 2021-10-05
  • 1970-01-01
  • 2011-01-07
  • 2020-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多