2023年就要过去,马上要跨如2024年。祝大家在新的一年,有个好收成。
一直以来不是很确定:
同样的的模板,在各个cpp分别出现,编译器要实现几份?
研究一下。
用命令行的编译方法,参考:
演练:在命令行上编译本机 C++ 程序 | Microsoft Learn
首先,启动vs的开发者控制台:
创建a.cpp,内容如下。
void fun1()
{
int x=0;
x++;
}
进行编译
(进编译成obj,如果不用选项/c,会进行link的动作,会报编译错误。加了/c,就只是编译)
查看,发现生成了 a.obj文件,它的尺寸是1KB:
用dumpbin查看符号
,注意,虽然fun1函数里用到了int类型的变量,但在dumpbin出来的时候,没有int的字样,因为它不是符号(symbol):
将a.cpp改一下,加入std::vector
用double实例化std::vector:
a.cpp
#include<vector>
void fun1()
{
std::vector<double> a;
int x=0;
x++;
}
重复刚才的编译命令:cl /c /EHsc a.cpp
发现a.obj的大小变成了8KB:
可以看出,模板的引入,对obj的个头影响。
看看符号,因为内容较多,所以输出到文本文件里:
搜索double字样,有65个匹配,说明出现了一些用double实例化的一些函数(symbol)。也可以看到vector的出现:
创建b.cpp,内容和a.cpp一样
b.cpp
#include<vector>
void fun1()
{
std::vector<double> a;
int x=0;
x++;
}
然后对b.cpp进行编译:
观察b.obj的大小,发现也是8KB大小
compare一下a.obj和b.obj:
发现,二进制应该是一致的。
这就说明了,对于每个cpp编译产生自己的obj文件,都会独自对模板进行实例化。这就是重复的内容。消耗了编译时间,增加了编译出来的obj的大小。
也可以同时对a.cpp和b.cpp进行编译,可以同时生成a.obj和b.obj:
a.cpp
#include<vector>
void fun1()
{
std::vector<double> a;
int x=0;
x++;
}
b.cpp
#include<vector>
void fun2()
{
std::vector<double> a;
int x=0;
x++;
}
hello.cpp
#include <iostream>
using namespace std;
int main()
{
cout << "Hello, world, from Visual C++!" << endl;
}
编译出hello.exe
hello.exe文件的大小是189KB,比a.obj、b.obj和hello.obj加起来都大
各个obj里的重复的symbol会不会合并起来
分别在a.cpp和b.cpp里出现的std::vector<double>在最后link的时候,应该是被合并成了一份。但这个例子说明不了。
实际项目说明了会合并
我们项目里的一个例子可以说明:
obj加起来超过2G,最后生成的dll只有12MB。(debug版)