一、什么是GCC?
GCC(the GNU Compiler Collection)GCC是GNU编译器集合,它包括了C/C++、Objective-C、Fortran、Ada和Go语言的前端和对应的库(libstdc++)GCC初衷是为完全免费的GNU系统编写的编译器。
二、程序编写到执行过程是怎么样的?
一个C程序从编辑到执行需要经过以下过程:
三、编译过程中文件内容的变化
编译一共需要处理四个文件(CISO):
- 源代码文件(*.c)
- 预处理文件(*.i)
- 汇编文件(*.s)
- 目标文件(*.o)
最后一步处理目标文件的过程称为链接,链接后将生成可执行或者库。下面通过观察处理的中间代码(CISO)建立编译过程的直观感受:
假如我编辑并保存了如下程序
//gcctest.cpp
#include <iostream>
using namespace std;
#define AAA 33333
int main()
{
double a=3.14;//ordinary variable
double &r=a;//ordinary referenece
cout<<r<<endl;//read ok
r=41.3;//write ok
cout<<r<<endl;
cout<<AAA<<endl;
double b=3.14;
const double &rr =b;//read only, restrict its own right
cout<<rr<<endl;//read ok
//rr=41.3;//write not ok
//cout<<rr<<endl;
const double c=3.14;
// double &rrr=c;//reference trying to obtain read and write right failed
// cout<<rrr<<endl;
// rrr=41.3;
// cout<<rrr<<endl;
const double d=3.14;
const double &rrrr=d;
cout<<rrrr<<endl;
//rrrr=41.3;
//cout<<rrrr<<endl;
}
3.1 预处理 -E(Pre-pocessing)xxx.c->xxx.i
预处理会做三件事情,为编译做准备:
- 宏变量替换
- 头文件展开
- 注释去除
命令格式:gcc -E xxx.c
g++ gcctest.cpp -o app.i
这个-o
其实指定生成文件名字标识(不指定默认生成a.out
)
这一阶段生成的文件(xxx.i),还是可以很容易阅读:
//...头文件展开部分
using namespace std;
int main()
{
double a=3.14;
double &r=a;
cout<<r<<endl;
r=41.3;
cout<<r<<endl;
cout<<33333<<endl;
double b=3.14;
const double &rr =b;
cout<<rr<<endl;
const double c=3.14;
const double d=3.14;
const double &rrrr=d;
cout<<rrrr<<endl;
}
3.2 编译 -S(Compiling) xxx.i->xxx.s
编译过后的文件称为汇编文件。命令格式:g++ xxx.i
,这里对上一部分的.i文件进行了处理:
g++ app.i -S -o app.s
仍然是个普通的文本文件,不过语言是汇编:
.file "class0919.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 $80, %rsp
//... 省略了一大段汇编语言
.LC1:
.long 1717986918
.long 1078240870
.hidden __dso_handle
.ident "GCC: (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0"
.section .note.GNU-stack,"",@progbits
3.3 汇编 -c(Assembling) xxx.s->xxx.o
汇编文件汇编后的文件类型是一个二进制文件,编译过程中叫做目标文件,基本上人是没法读懂了:
乱码
3.4 链接(Linking) xxx.o->xxx
对目标文件的集合称为可执行文件。命令g++ xxx1.o xxx2.o
g++ -o eee
内容一样是乱码,使用file命令可以查看其类型:
eee: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=06ad229f773d4211a1a47719e43e93cc2886c5c3, not stripped
可以它是一个可执行程序。
四、GCC其他选项
GCC不仅具有编译成可执行的功能,还具有添加有用信息(-g)和打印信息(调试),甚至还可以调节优化等级(-On)。
option | meaning |
---|---|
-o | 指定生成的文件名 |
-E | 仅执行编译预处理 |
-S | 将C代码转换为汇编代码 |
-wall | 显示警告信息 |
-c | 仅执行编译操作,不进行连接操作 |
-g | 生成调试信息,不加选项不能进行gdb调试 |
查看GCC版本:
gcc --version
gcc -v
五、常见应用
5.1 无选项编译
无选项编译直接生成名为a.out
的可执行文件
gcc test.c
将test.c预处理、汇编、编译并链接成可执行文件a.out
。
5.2 选项 -o
gcc test.c -o test #省略了-c选项,完整的gcc -c test.c -o test,不会产生中间文件
和无选项编译一样,只不过生成的可执行名字变成了test
。
5.3 选项 -E
仅预处理:
gcc -E test.c -o test.i
将test.c预处理输出test.i文件。
5.4 选项 -c
仅编译:
gcc -c test.s
将汇编输出文件test.s编译输出test.o文件。
5.5 选项 -S
仅汇编:
gcc -S test.i
将预处理输出文件test.i汇编成test.s文件。
5.6 选项-O
优化选项:
gcc -O1 test.c -o test
使用编译优化级别1编译程序。级别为1~3,级别越大优化效果越好,但编译时间越长
5.7 多个文件一起编译
第一次生成可以使用:
gcc testfun.c test.c -o test
一起编译+链接生成test可执行
仅对部分源文件进行了修改,使用-o选项更快:
gcc -c testfun.c #将testfun.c编译成testfun.o
gcc -c test.c #将test.c编译成test.o
gcc -o testfun.o test.o -o test #将testfun.o和test.o链接成test
[1] 20220622,将原有的文字部分改成流程图