2014-09-02 40 views
2

在他的FAQ中,Bjarne Stroustrup说当用gcc -O2编译时,使用C和C++的hello world的文件大小是相同的。为什么C++ Hello World二进制文件大于等效的C二进制文件?

参考: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; 
} 

这里我编译,以及大小是不同的:

[email protected]:~/hello$ ls 
hello.c hello.cpp 
[email protected]:~/hello$ gcc -O2 hello.c -o c.out 
[email protected]:~/hello$ g++ -O2 hello.cpp -o cpp.out 
[email protected]:~/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 
[email protected]:~/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 

我用\n替换了std::endl,它使二进制变小。我认为这种简单的内容会被内联,而我感到失望的是它不是。

另外哇,优化的组件有几百行汇编输出?我可以用5个汇编指令使用sys_write来编写hello world,那么所有额外的东西是什么?为什么C在堆栈上放置了一些额外的设置?我的意思是,为什么像50个字节的组件vs 8kb的C?

+9

不,他没有这样说。他说*“在2004年,我在Unix上使用gcc -O2进行测试,并且两个版本(iostreams和stdio)产生相同的大小。”* – 2014-09-02 01:07:01

+4

您的问题具体是什么?另外,我认为说Bjarne对此撒谎是有点强烈的。有可能在旧系统上使用较旧的编译器时,二进制文件具有相同的大小(即使在较新的系统中这种情况也是如此)。 – templatetypedef 2014-09-02 01:07:07

+0

现在剥离符号... – 2014-09-02 01:09:31

回答

4

我认为他把半千字节视为舍入误差。两者都是“9千字节”,这就是你在典型的文件浏览器中看到的。它们并不完全一样,因为在C和C++库的底层,它们是完全不同的。如果你已经熟悉你的反汇编程序,你可以看到自己差异的细节。

“额外的东西”是为了从标准库shlib导入符号和处理C++异常。奇怪的是,很多GCC编译的C可执行文件被C++异常处理表占用。我还没有想出如何使用GCC去除它们。

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

实际上,单个kilobytes在任何带动态加载库的系统上都很少见。诸如嵌入式系统上的独立代码需要包括它所使用的标准库功能,而C++标准库往往比其C对象更重 - 特别是<iostream><stdio.h>

+0

_“我还没弄清楚如何使用GCC去除它们”_ -fno-exceptions'通常会阻止使用异常。在'stdlibC++'中覆盖了一个弱函数,它提供了用于异常处理的terminate('terminate_handler')代码。 – 2014-09-02 01:17:03

+1

@πάνταῥεῖ当然,这是我第一次尝试:v)。让我知道如果你发现有用的东西。这个问题不会产生异常,它支持调用使用异常的函数。 – Potatoswatter 2014-09-02 01:18:14

+0

我将不得不检查我的同事的工作,他通过重写提到的弱函数来省略标准未捕获的异常处理代码。我现在不记得确切的名字。 – 2014-09-02 01:20:42

7

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

[email protected]:~/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 world可以比基于printf的hello世界更小,因为编译器可以精确地看到使用了哪些重载版本0123,并优化了不需要的代码(例如昂贵的浮点打印),而printf对格式字符串的使用使得这在一般情况下是困难的并且一般不可能。然而,我从来没有见过一个C++实现,其中基于静态链接的基于iostream的hello程序可以接近任何接近小于,小于基于printf的C的实例。