对于C/C++代码,生成可执行文件前经过如下若干步:
- 预处理器:源代码 .cpp/.h/.c 经过预处理器处理后生成 .i 的代码文件
- 编译器:将 .i 文件翻译成 .s 的汇编代码
- 汇编器:将 .s 的汇编代码翻译成 .o 的目标代码
- 链接器:将 .o 的目标代码与库文件、其他目标代码等链接生成最终的可执行程序。
我们创建了h e l l o w o r l d . c p p helloworld.cpphelloworld.cpp文件。
#include <iostream>
#define PI 3.14
int main(){
double r = 2;
double S = PI * r * r;
std::cout << S << std::endl;
return 0;
}
1.直接编译
| 命令 | 参数 | 备注 |
|---|
| g++ helloworld.cpp -o helloworld.exe | -o filename | 将源文件编译链接,生成可执行程序filename |
接下来我们可以通过. / h e l l o w o r l d . e x e ./helloworld.exe./helloworld.exe执行。
2.预处理
- 在预处理阶段,可以生成预处理后的代码文件h e l l o w o r l d . i helloworld.ihelloworld.i
- 预处理阶段,进行了宏替换,注释删除等工作。
| 命令 | 参数 |
|---|
| g++ helloworld.cpp -E -o helloworld.i | -E |
- 若直接执行g + + h e l l o w o r l d . c p p − E g++ helloworld.cpp -Eg++helloworld.cpp−E ,则默认将预处理结果输出至终端,并不会生成 − i -i−i文件,因此一般-E配合-o使用。
- 预处理后的h e l l o w o r l d . i helloworld.ihelloworld.i文件如下。共28000+行,因此只展示了开头与最后的若干行。
# 1 "helloworld.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "helloworld.cpp"
# 1 "/usr/include/c++/7/iostream" 1 3
# 3 "helloworld.cpp"
int main(){
double r = 2;
double S = 3.14 * r * r;
std::cout << S << std::endl;
return 0;
}
- 可以看出,源文件的注释经过预处理后被删除了。同时,宏P I PIPI也被替换成了3.14.
3.编译成汇编代码
| 命令 | 参数 |
|---|
| g++ helloworld.i -S | -S |
- 也可以使用-o重新制定生成的-s文件的文件名。
- 执行命令后,最终生成了名为h e l l o w o r l d . s helloworld.shelloworld.s的汇编代码。同样,只展示前面若干行。
.file "helloworld.cpp"
.text
.section .rodata
.type _ZStL19piecewise_construct, @object
.size _ZStL19piecewise_construct, 1
_ZStL19piecewise_construct:
.zero 1
.local _ZStL8__ioinit
.comm _ZStL8__ioinit,1,1
.text
.globl main
.type main, @function
main:
.LFB1493:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $32, %rsp
movsd .LC0(%rip), %xmm0
movsd %xmm0, -16(%rbp)
movsd -16(%rbp), %xmm1
movsd .LC1(%rip), %xmm0
mulsd %xmm1, %xmm0
movsd -16(%rbp), %xmm1
mulsd %xmm1, %xmm0
movsd %xmm0, -8(%rbp)
movq -8(%rbp), %rax
;
;省略
4.汇编,生成目标文件
| 命令 | 参数 |
|---|
| g++ helloworld.s -c | -c |
- 生成了h e l l o w o r l d . o helloworld.ohelloworld.o目标代码二进制文件,无法直接打开。
- 同样,可以使用-o重新执行生成文件的文件名。
5.链接
| 命令 | 参数 |
|---|
| g++ helloworld.o -o helloworld.out | -c |
- 在Linux系统下,生成h e l l o w o r l d . o u t helloworld.outhelloworld.out可执行文件。
- 使用 . / h e l l o w o r l d . o u t ./helloworld.out./helloworld.out执行,输出面积12.56。