在他的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,为什么?
答案 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>
。