编译后的C++可执行文件很大?

6
在使用C编程一段时间后,我决定开始学习C++。这让我有些困扰,因为在C中标准的“hello world”程序通常包含所有编译器添加的内容,大小约为16KB(使用stdio)。
然而,当我用C++创建hello world可执行文件时,文件大小达到了约470KB!我改用cstdio代替iostream,认为这会有所不同,事实也确实如此。
我的问题是: 为什么当我包含iostream时,可执行文件的大小会急剧增加?
编辑:我正在使用G++(带有Dev-CPP IDE,但我可以弄清楚如何添加CL参数)。

我想指出的是,Dev-C++自带一个非常老旧的GCC版本。考虑迁移到wxDev-C++或Code::Blocks,它们都更加更新。 - greyfade
6个回答

7

简而言之,即符号。

C++标准库向您的程序引入了大量符号,因为大部分库主要存在于头文件中。

在发布模式和无调试符号的情况下重新编译程序,您可以轻松地期望程序变得更小。(如果去掉符号,则会更小。)

以下是此事实的快速演示:

$ cat hello.c
#include <stdio.h>
int main() {
    printf("%s\n", "Hello, world!");
    return 0;
}
$ cat hello.cpp
#include <iostream>
int main() {
    std::cout << "Hello, world!\n";
    return 0;
}
$ gcc hello.c -o hello-c
$ g++ hello.cpp -o hello-cpp
$ gcc hello.c -ggdb -o hello-c-debug
$ g++ hello.cpp -ggdb -o hello-cpp-debug
$ gcc hello.c -s -o hello-c-stripped
$ g++ hello.cpp -s -o hello-cpp-stripped
$ gcc hello.c -s -O3 -o hello-c-stripped-opt
$ g++ hello.cpp -s -O3 -o hello-cpp-stripped-opt
$ ls -gG hello*
-rwxr-xr-x 1  6483 Nov 14 15:39 hello-c*
-rw-r--r-- 1    79 Nov 14 15:38 hello.c
-rwxr-xr-x 1  7859 Nov 14 15:40 hello-c-debug*
-rwxr-xr-x 1  7690 Nov 14 15:39 hello-cpp*
-rw-r--r-- 1    79 Nov 14 15:38 hello.cpp
-rwxr-xr-x 1 19730 Nov 14 15:40 hello-cpp-debug*
-rwxr-xr-x 1  5000 Nov 14 15:45 hello-cpp-stripped*
-rwxr-xr-x 1  4960 Nov 14 15:41 hello-cpp-stripped-opt*
-rwxr-xr-x 1  4216 Nov 14 15:45 hello-c-stripped*
-rwxr-xr-x 1  4224 Nov 14 15:41 hello-c-stripped-opt*

我无法解释为什么使用G++在Windows上构建程序会产生如此大的可执行文件,但在任何其他平台上,符号是导致文件大小增大的主要因素。目前我没有Windows系统的访问权限,因此无法进行测试。


嗨,感谢您抽出时间进行这些结果。我在Windows中使用“-s -O3”标志进行了此操作,文件大小从475kb减少到263kb。这有所帮助,但我还能做更多吗? - Saustin
1
@Saustin:使用更新的编译器。你正在使用一个非常老的编译器。它可能带有一些陈旧的东西,这些东西不会被添加到更新版本中。Dev-C++已经不再维护了,所以没有理由继续使用它,因为有很多其他更好的选择。我的意思是,最近的发布版本是在2005年! - greyfade
这是真的;你有什么编译器推荐吗?(PS:很抱歉验证时间这么长!) - Saustin
1
@Saustin:Code::Blocks打包的MinGW版本是最新的。wxDev-C++打包的MinGW版本(与您使用的版本不同)也是最新的。您还可以使用Visual Studio 2010 Express,它也是最新的。 - greyfade

6
由于使用iostreams,您已经拖入了大部分标准库。不过这只是一次性的事情,随着程序变得越来越大,它将会变得越来越不重要。
但是,您可能想要使用共享库版本的标准库进行编译,大多数编译器/操作系统都可以让您这样做,这样您就不必在可执行文件中包含所有标准库。请问您使用的是哪个编译器,我们可以为您提供相应的建议。
例如,在Windows下使用VC命令行,可以使用/MD命令行选项。

2
我猜测通过包含<iostream>,你间接地包含了许多STL的组件,例如<string>,而<string>又包含了<vector>等。

将这个答案转化为C语言术语,就是使用 putc 与 printf 之间的区别。相对于简单的 putc 函数而言,printf 代码具有大量的功能,会使得你的 C 可执行文件变得比较庞大。对于 Saustin 的情况而言,<iostream> 方法相对于 printf 来说是“巨大的”,而 STL 相对于 <iostream> 来说也是“巨大的”。 - franji1

2

这更多地是由你使用的编译器(和选项)造成的结果,与其他任何因素都无关。使用 MS VC++,根据我使用的编译器标志,可以得到从约8K到约110K不等的大小范围。使用 MinGW,我得到大约24-25K的大小(同样取决于标志)。

以防你想知道,我猜 VC++ 给出的较大范围主要是我更了解它的标志的结果。即使我更了解 MinGW 的标志,它可能只覆盖更小的范围,但由于我对其标志的知识有限,我接受它默认的大部分内容;我知道如何打开和关闭优化,但必须非常仔细地查看才能做更多的事情。


1

MinGW (g++) 编译大文件时速度较慢。
例如,使用 iostreams 的相同的“hello world”程序在 VC++(使用静态链接 CRT)下编译为约100KB,在 g++ 下编译为约470KB。


即使使用最新的Visual Studio和带有GCC 7.2.0的MinGW w-64(使用CMake用于发布构建的标准编译器标志),这仍然是正确的。 - clocktown

1

这是虚假C++面试中实际上有点真实的一个方面 :)

你知道吗,在AT&T时,我们有了第一个C++编译器,我编译了“Hello World”,简直不敢相信可执行文件的大小。2.1MB

什么?编译器从那时起已经发展了很长一段时间。

是吗?在最新版本的g++上尝试一下 - 你几乎得不到半兆字节的变化。


1
并不是非常有帮助,但幽默能带来些许帮助。 - Saustin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接