一开始编译C++代码的时候可能会对编译的错误觉得很难理解,搞不清楚究竟是哪里错了。了解编译过程,能够更好的处理编译错误。
编译单元:当一个c或cpp文件在编译时,预处理器首先递归包含头文件,形成一个含有所有 必要信息的单个源文件,这个源文件就是一个编译单元。
目标文件:目标文件包含着机器代码(可直接被计算机中央处理器执行)以及代码在运行时使用的数据,此外还包括其他调试信息。
在VC中编译过程会分成以下三步:
1,预处理
2,生成目标文件
3,链接成可执行文件
1,预处理
将头文件加载进来,处理各种#define,如:宏,预编译条件,生成一个独立的编译单元。
可以通过以下的命令来生成独立的编译单元。
cl /EP test.cpp > test_p.cpp
这个命令的意思是,把源文件生成编译单元并写到test_p.cpp中。举个例子
下面是源文件代码
// test.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <windows.h> #include <iostream> #define MAX(a,b) (a>b?a:b) #define PI 3.1415927 #ifdef UNICODE typedef wchar_t MTCHAR; #else typedef char MTCHAR; #endif // UNICODE
int _tmain(int argc, _TCHAR* argv[]) { std::cout << MAX(10, 20) << std::endl; std::cout << PI << std::endl; MTCHAR *str = _T("hello world!"); _tprintf(_T("%s\n"), str); return 0; }
源代码中包含了三个头文件,定义一个表达式的宏,一个常量的宏,和使用预编译条件定义了一个字符类型
我们通过上面的命令生成新的文件,包含文件指令会把头文件引进来,把宏在代码中替换掉,把预编译条件指令处理。
/* 这里省略掉大量的头文件代码,整个文件总共有三十多万行。 */ typedef char MTCHAR; int main(int argc, _TCHAR* argv[]) { std::cout << (10>20?10:20) << std::endl; std::cout << 3.1415927 << std::endl; MTCHAR *str = "hello world!"; printf("%s\n", str); return 0; }
也可以在cl命令中加入宏UNICODE和_UNICODE,这样可以更清晰地看到预处理条件指令的处理效果
cl /EP /D "UNICODE" /D "_UNICODE" test.cpp > test_p.cpp
生成的编译单元
/* 这里省略掉大量的头文件代码,整个文件总共有三十多万行。 */ typedef wchar_t MTCHAR; int wmain(int argc, _TCHAR* argv[]) { std::cout << (10>20?10:20) << std::endl; std::cout << 3.1415927 << std::endl; MTCHAR *str = L"hello world!"; wprintf(L"%s\n", str); return 0; }
MTCHAR已经被定义为wchar_t而不是char了,而且字符串也是wchar格式。
2,生成目标文件
将编译单元进行编译,生成目标文件(.obj文件)。这里通常分两个阶段:首先生成汇编语言,然后适用汇编生成机器码。
通过刚才生成的编译单元来生成目标文件
cl /c test_p.cpp
已经生成里机器码,所以不贴文件内容了。
3,链接
链接的任务就是把目标文件连起来生成可执行文件。
link test.obj
使用这个命令就能生成exe文件。
4,cl命令
cl命令有几个跟标准库有关的选项:/ML,/MLd,/MT,/MTd,/MD,/MDd。这些选项是想告诉编译器应用程序需要什么标准库。
/ML:(缺省选项)对应单线程静态的标准库。
/MT:对应多线程静态标准库 (libcmt.lib) ,此时编译器会自动定义 _MT 宏。
/MD:对应多线程 DLL 版 ( 导入库 msvcrt.lib , DLL 是msvcrt.dll) ,编译器自动定义 _MT 和 _DLL两个宏。
/MLd:对应调试单线程静态标准库 (libcd.lib) 。
/MTd:对应调试多线程静态标准库 (libcmtd.lib) 。
/MDd:对应调试多线程 DLL 标准库 ( 导入库msvcrtd.lib, DLL 是msvcrtd.dll) 。