李太吉的技术博客

人生到处知何似 应似飞鸿踏雪泥

0%

与编译器编译输出大小相关的某些因素

与编译器编译输出大小相关的某些因素

问题背景

在编译一个极其简单的 C++ 入门示例( test.cpp )的时候,发现 Code::Blocks 编译的结果比 Visual Studio 编译的结果大许多。

研究过程

我们使用如下工具,对 test.cpp 文件进行编译测试,探究与编译器编译输出大小相关的因素。

测试环境

  • Code::Blocks 17.12GCC 5.1.0
  • Visual Studio 2017MSVC++ 15.0
  • GCC 8.1.0
1
2
3
4
5
6
7
8
9
10
//test.cpp

#include <iostream>
using namespace std;

int main()
{
cout << "Hello World!" << endl;
return 0;
}

问题重现

一般来说,不同的 IDE 都有不同的默认编译选项。我们先用命令行复原模拟 Code::Blocks 17.12Visual Studio 2017 的编译过程。

1
2
3
// Code::Blocks 17.12
mingw32-g++ test.cpp -c -o test.o
mingw32-g++ test.o -o test.exe

输出大小为 1528KB 。对于如此简单的代码,这个大小可以说相当大了。
VS 的编译过程较为复杂,我们不再用命令行模拟,但 VS 的编译输出大小只用 193KB

问题定位

问题可以重现,也就代表这个问题背后有较为稳定的原因,多半是代码造成的结果,而不是玄学导致的,我们也就不用玄学排错了。由于很难用命令行模拟VS编译,我们下面就主要使用 GCC 5.1.0 进行测试。

很容易想到是不是静态链接和动态链接的原因,我们先用 -static 编译选项看一下静态链接编译输出的大小。

1
2
3
// GCC 5.1.0
mingw32-g++ test.cpp -c -o test.o
mingw32-g++ test.o -static -o test.exe

输出大小为 1528KB ,和之前完全一样。为什么静态链接会和动态链接的编译输出一样大?我们查看 GCC 的安装目录,我们可以看到它压根就没有动态库,全部是 .a 静态链接库文件。

image

至此可以说仅就这个问题来说算是找到答案了。 Code::Blocks 下载时配套的编译器为GCC 5.1.0,而该编译器没有携带动态库,只支持静态链接(也就是说不管添不添加-static编译选项,都是静态链接)。相反,VS下载时一并下载了Windows SDK,里面包含了 C Runtime Library (C运行时库),而且既有静态运行时库,也有动态运行时库,因此 Visual Studio 支持静态链接和动态链接, Visual Studio 使用动态链接编译的结果显然比Code::Blocks使用静态链接 编译的结果小许多。

我们用携带动态链接库的 GCC 8.1.0 编译该文件,得到的输出结果大小只有56KB,甚至比 VS 的还要小(当然通过修改编译选项, VS 的输出结果也能做到这么小,甚至更小,毕竟GCC开源, VS 有微软的技术支撑,而且 GCC 本来就不是 Windows 平台的原生编译器,对 Windows 的支持一定没有微软自家好)。

拓展研究

ReleaseDebug

我们比较ReleaseDubug两个版本的编译输出。

1
2
3
4
5
// GCC 8.1.0
// Debug
g++ test.cpp -g -o test.exe
// Release
g++ test.cpp -s -o test.exe

Debug 版有 75KBRelease 版有 56KB 。对于我们的测试代码差别不大,但大型项目的 ReleaseDebug 版本大小就会相差悬殊。

编译器的版本

不同的编译器或者同一编译器的不同版本生成的编译输出大小可能就不同。

1
2
// GCC 8.1.0
g++ test.cpp -static -o test.exe

生成的编译输出大小为2552KB,比GCC 5.1.0还要大。猜测可能是因为要支持更新的C++ 20标准,链接了更多的文件。

IDE和编译器添加的其它优化

总结

与编译器编译输出大小相关的因素一般有如下几个原因

  1. 编译器的链接选项不同,静态链接比动态链接更小(支持动态链接的前提是你要有动态库,不然编译选项是不管用的)。
  2. 编译器可以生成 Release 版和 Debug 版,后者包含调试信息,一般来说体积更大。
  3. 编译器不同,更新版本的编译器生成的代码可能更小更小或更大。
  4. IDE 和编译器添加了其他的优化选项。