为什么C ++ Hello World二进制文件大于等效的C二进制文件?

时间:2014-09-02 01:03:30

标签: c++ c size

在他的FAQ中,Bjarne Stroustrup说当用gcc -O2编译时,使用C和C ++的hello世界的文件大小是相同的。

参考:http://www.stroustrup.com/bs_faq.html#Hello-world

我决定尝试这个,这是C版本:

#include <stdio.h>

int main(int argc, char* argv[])
{
    printf("Hello world!\n");
    return 0;
}

这是C ++版本

#include <iostream>

int main(int argc, char* argv[])
{
    std::cout << "Hello world!\n"; 
    return 0;
}

我在这里编译,尺寸不同:

r00t@wutdo:~/hello$ ls
hello.c  hello.cpp
r00t@wutdo:~/hello$ gcc -O2 hello.c -o c.out
r00t@wutdo:~/hello$ g++ -O2 hello.cpp -o cpp.out
r00t@wutdo:~/hello$ ls -l
total 32
-rwxr-xr-x 1 r00t r00t 8559 Sep  1 18:00 c.out
-rwxr-xr-x 1 r00t r00t 8938 Sep  1 18:01 cpp.out
-rw-r--r-- 1 r00t r00t   95 Sep  1 17:59 hello.c
-rw-r--r-- 1 r00t r00t  117 Sep  1 17:59 hello.cpp
r00t@wutdo:~/hello$ size c.out cpp.out
   text    data     bss     dec     hex filename
   1191     560       8    1759     6df c.out
   1865     608     280    2753     ac1 cpp.out

我将std::endl替换为\n,它使二进制文件更小。我认为这个简单的东西会被内联,而且我很失望,不是。

同样哇,优化的组件有数百行组装输出?我可以使用sys_write用5个汇编指令编写hello world,所有额外的东西是什么?为什么C会在堆栈上添加一些额外的东西来设置?我的意思是,像50个字节的汇编和8kb的C,为什么?

2 个答案:

答案 0 :(得分:7)

您正在查看容易被误解的混合信息。 8559和8938字节的文件大小在很大程度上没有意义,因为它们主要是带有符号名称和其他misc信息的头文件,至少用于最小的调试目的。 有些有意义的数字是您稍后添加的size(1)输出:

r00t@wutdo:~/hello$ size c.out cpp.out
   text    data     bss     dec     hex filename
   1191     560       8    1759     6df c.out
   1865     608     280    2753     ac1 cpp.out

您可以使用-A size选项获得更详细的细分,但简而言之,这里的差异相当微不足道。

更有意思的是,Bjarne Stroustrup从未提及他是在谈论静态还是动态链接。在您的情况下,两个程序都是动态链接的,因此大小差异与stdio或iostream的实际大小成本无关;您只是测量调用代码的成本,或者(更可能是基于其他注释/答案)C ++异常处理支持的基本开销。现在,有一个共同的主张是,基于静态链接的C ++基于iostream的hello世界甚至可以比基于printf的hello世界更小,因为编译器可以确切地看到使用了operator<<的重载版本并且优化掉不需要的代码(例如昂贵的浮点打印),而printf使用格式字符串使得这在常见情况下变得困难并且通常是不可能的。但是,我从来没有见过一个C ++实现,其中基于静态链接的基于iostream的hello程序可能接近于小于基于printf的基于{{1}}的C语言。

答案 1 :(得分:4)

我认为他将半千字节视为舍入误差。两者都是“9千字节”,这就是您在典型的文件浏览器中看到的内容。它们并不完全相同,因为在引擎盖下,C和C ++库是完全不同的。如果您已经熟悉了反汇编程序,那么您可以自己查看差异的详细信息。

“额外的东西”是为了从标准库shlib导入符号和处理C ++异常。奇怪的是,大部分GCC编译的C可执行文件都被C ++异常处理表占用。我还没弄清楚如何使用GCC剥离它们。

endl 内联,但它包含打印\n字符并刷新流的调用,这些内容未内联。尺寸的差异是由于从标准库中导入的。

事实上,在具有动态加载库的任何系统上,单个千字节很少。诸如嵌入式系统之类的自包含代码需要包含它使用的标准库功能,并且C ++标准库往往比它的C对应物重 - 特别是<iostream><stdio.h>