对于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.cpp
helloworld.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.i
helloworld.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 -E
g++helloworld.cpp−E ,则默认将预处理结果输出至终端,并不会生成
−
i
-i
−i文件,因此一般-E配合-o使用。
- 预处理后的
h
e
l
l
o
w
o
r
l
d
.
i
helloworld.i
helloworld.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
PI
PI也被替换成了3.14.
3.编译成汇编代码
命令 | 参数 |
---|
g++ helloworld.i -S | -S |
- 也可以使用-o重新制定生成的-s文件的文件名。
- 执行命令后,最终生成了名为
h
e
l
l
o
w
o
r
l
d
.
s
helloworld.s
helloworld.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.o
helloworld.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.out
helloworld.out可执行文件。
- 使用
.
/
h
e
l
l
o
w
o
r
l
d
.
o
u
t
./helloworld.out
./helloworld.out执行,输出面积12.56。