对于相同的c ++源文件,其gcc可执行文件在Windows中比在Linux中大655倍。为什么这么大的差异?

时间:2014-01-22 14:15:27

标签: c++ linux windows gcc iostream

我正在使用GCC 4.8.2在我的Windows 8.1,Intel i7-3517U 64位笔记本电脑上测试这个简单的c ++代码。

#include<iostream>

using namespace std; 

int main(int argc, char **argv){
   cout << "This test code will simply display any arguments passed." << endl ;
   for(int i=0; i<argc; i++){
      cout << argv[i] << endl ;
   }
   return 0 ;
}

令人惊讶的是,编译后,可执行文件的结果为 5905KB 。出于好奇,我尝试在Linux Fedora 20 64位机器上使用相同的GCC版本编译相同的文件。可执行文件只是 9KB

使用g++ -Ox -o fileWithOx.exe file.cpp(x = 1,2,3,s)进行各种优化后,Windows可执行文件的大小几乎相同。在做了一些研究之后,在MinGW's advise之后我尝试使用strip g++ -s -o fileWithStrip.exe file.cpp编译它们而没有调试信息,但是可执行文件仍然 597KB 大。

另一方面,对于相同的选项,Linux可执行文件只有 6-13KB

做一些实验,some more research&amp; stack overflowing,我几乎确信巨大的大小是由于 iostream 链接到许多其他头文件和/或生成一些初始化代码。

但我怀疑是iostream既可以在Windows中使用,也可以在Linux中使用。那为什么这么大的差异呢?我知道Windows和Linux可执行文件的工作方式不同。 但是大了655倍,这不是有点极端吗?

3 个答案:

答案 0 :(得分:5)

差异可能不是由于编译而是链接版本阶段。

首先尝试仅编译,使用-c停止命令,例如类似于Unix的g++ -c code.cpp并在Windows环境中找到等效的标志。然后比较目标文件,它们应该是几乎相同的大小。这些目标文件(.o扩展名)仅包含代码到机器代码的转换。大小可能会有所不同,比如可能是2或3,但这是不相关的。

发生的事情是Windows的编译器可能在某些库上使用静态链接,因此可执行文件包含您在库中使用的代码。在Unix上,编译器可能会动态地链接所有内容,这表示库将在运行时加载而不包含在可执行文件中。

请参阅编译器文档以了解如何强制执行静态/动态链接。您应该知道,某些环境可能无法提供这两种类型的库......

答案 1 :(得分:2)

使用mingw g ++版本4.7.2在Windows下构建你的程序 - 我只获得10kb。不知道你是怎么设法把它膨胀到超过5MB。这是我在Code :: Blocks 13.12中按下Ctrl-F11时的cmd行和输出:

  

mingw32-g ++。exe -Wall -fexceptions -O2 -I“C:\ Program Files(x86)\ CodeBlocks \ MinGW \ include”-c C:\ Users \ enhzflep \ Documents \ code \ 001-sizeTestDeleteMe \ main .cpp -o obj \ Release \ main.o   mingw32-g ++。exe -o bin \ Release \ 001-sizeTestDeleteMe.exe obj \ Release \ main.o -s
  输出文件是bin \ Release \ 001-sizeTestDeleteMe.exe,大小为10.50 KB

答案 2 :(得分:1)

抱歉,我现在没有任何Windows框,但如果我相信这篇文章,

也许是因为你的Windows可执行文件静态链接到Mingw编译器套件附带的libstdc++.a,而Linux版本动态链接到像/usr/lib64/libstdc++.so.6这样的东西。后者是大多数Linux发行版的标准组件之一,可以通过动态链接器进行搜索,因此Linux g++可以安全地依赖它。但前者不是,所以也许Mingw g++决定采用静态链接。

以下文章(在Mingw GCC 4.4上)说,您可以告诉Mingw g++动态链接libstdc++.dll与cmd行选项-lstdc++_s

仅供参考,这就是我的Debian盒子上的小型C ++ exe与libstdc++.so.6动态链接的方式:

$ ldd valueInit
    linux-vdso.so.1 (0x00007fff641fe000)
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f20618e2000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f20615e4000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f20613cd000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2061021000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f2061c12000)
$ LANG=C ls -lH /usr/lib/x86_64-linux-gnu/libstdc++.so.6
-rw-r--r-- 1 root root 953K Jan  6 12:24 /usr/lib/x86_64-linux-gnu/libstdc++.so.6

libstdc++.so.6确实包含许多iostream函数等的定义。

$ readelf -sW /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep stream | c++filt | head -3
   135: 0000000000084360    51 FUNC    WEAK   DEFAULT   12 std::money_get<char, std::istreambuf_iterator<char, std::char_traits<char> > >::get(std::istreambuf_iterator<char, std::char_traits<char> >, std::istreambuf_iterator<char, std::char_traits<char> >, bool, std::ios_base&, std::_Ios_Iostate&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&) const@@GLIBCXX_3.4
   137: 00000000002e8ff0    24 OBJECT  WEAK   DEFAULT   23 typeinfo for std::basic_stringstream<char, std::char_traits<char>, std::allocator<char> >@@GLIBCXX_3.4
   138: 000000000009f1d0    15 FUNC    WEAK   DEFAULT   12 std::num_put<wchar_t, std::ostreambuf_iterator<wchar_t, std::char_traits<wchar_t> > >::put(std::ostreambuf_iterator<wchar_t, std::char_traits<wchar_t> >, std::ios_base&, wchar_t, void const*) const@@GLIBCXX_3.4