type
status
date
slug
summary
tags
category
icon
password
URL
程序的生命周期是从一个源程序(或者说源文件)开始的,即程序员通过编辑器创建并保存的文本文件。源程序实际上就是一个由值 0 和 1组成的位(又称为比特)序列,8 个位被组织成一组,称为字节。每个字节表示程序中的某些文本字符
大部分计算机使用 ASCII 标准来表示文本字符
- 用一个唯一的单字节大小的整数值息来表示每个字符
- 程序是以字节序列的方式储存在文件中的
源文件表示方法说明了一个基本思想∶ 系统中所有的信息——包括磁盘文件、内存中的程序、内存中存放的用户数据以及网络上传送的数据,都是由一串比特表示的。
一、编译过程
首先及其是无法识别C语言这样的高级语言的语法的,所以每一条C语句都必须被一个解析器转化为低端的机器语言。然后这些指令按照一种称为可执行目标程序的格式打好包,并以二进制磁盘文件的形式存放起来。
而GCC就是扮演着解析器的工作,GCC 编译器读取源程序文件 xxx.c,并把它翻译成一个可执行目标文件xxx。这个翻译过程可分为四个阶段完成,如下图所示
执行这四个阶段的程序(预处理器、编译器、汇编器和链接器)一起构成了编译系统(compilation system)

1.1 预处理阶段
熟悉C语言的应该知道,在每个c代码开头会使用 # include头文件。而预处理阶段就是对这部分进行处理。
预处理器(cpp)
根据以字符#开头的命令,修改原始的C程序。比如#include <stdio.h>
命令告诉预处理器读取系统头文件stdio.h的内容,并把它直接插入程序文本中。结果就得到了另一个C程序,通常是以.i作为文件扩展名。下面以一个hello.c的源码进行演示
使用如下指令将hello.c代码进行预处理,转成hello.i

我们打开这个文件,发现里面增加了很多代码


1.2 编译阶段
编译器(ccl)
将文本文件hello.i翻译成文本文件hello.s,它包含一个汇编语言程序。使用如下指令将hello.i转成hello.s


1.3 汇编阶段
这部分就是将汇编文件转换成目标文件xxx.o,
汇编器(as)
将xxx.s翻译成机器语言指令,把这些指令打包成一种叫做可重定位目标程序(relocatable object program)的格式,并将结果保存在目标文件hello.o中。使用如下的指令将hello.s转成hello.o

1.4 链接阶段
我们在源码中调用的一些函数,比如printf,这个是C编译器提供的标准C库中的一个函数。printf函数的源码实现存在于一个名为printf.o的单独文件中,所以我们在编译我们自己程序的时候使用到这个printf函数,我们就需要将printf.o以某一种形式合并到我们自己的程序中。
而链接器就负责这个工作,他的执行结果就是一个可执行程序,是可以被加载到内存中,被系统运行。
使用如下指令将hello.o转成hello

二、C语言的编译
上一章节主要介绍C语言编译的几个阶段,并用hello.c做了演示。本章节完全从指令角度来处理C语言的编译,分为可执行程序/动态库/静态库的编译。
首先介绍以下C语言文件相关的后缀以及编译参数
Suffix | File Contains |
.a | 静态库 |
.c | 源文件,也有.cc |
.h | 头文件 |
.i | 预处理文件 |
.o | 目标文件 |
.s | 汇编代码 |
.so | 动态库 |
parameters | 解释 |
-E | 告诉编译器只进行预处理操作 |
-o | 把预处理的结果输出到指定文件 |
-S | 告诉编译器进行预处理和编译成汇编语言操作 |
-c | 生成目标文件 *.o |
2.1 可执行程序
2.1.1 预处理
2.1.2 汇编
2.1.3 生成目标文件
2.1.4 生成可执行程序
2.2 静态库
2.2.1 编译成.o
2.2.2 编静态库
2.2.3 链接可执行文件
2.2.4 实例
以下面这个例子为例,将两个helloworld.c hellolinux.c编译成libhello.a,然后在main程序中调用编译。
helloworld.c
hellolinux.c
main.c
输出文件

输出结果

如果我们在编译时不将此libhello.a带入编译,则会出现

2.3 动态库
2.3.1 编译二进制.o文件
2.3.2 编动态库
2.3.3 链接库到可执行文件
2.3.4 实例
以下面这个例子为例,将两个helloworld.c hellolinux.c编译成libhello.so,然后在main程序中调用编译。
helloworld.c、hellolinux.c和main.c的源码与上一章一致

三、C++文件编译
首先介绍以下C++语言文件相关的后缀以及编译参数
Suffix | File Contains |
.a | 静态库 |
.c, .c++, .cc, .cp, .cpp, .cxx | 源文件,也有.cc |
.h | 头文件 |
.i, .ii | 预处理文件 |
.o | 目标文件 |
.s | 汇编代码 |
.so | 动态库 |
parameters | 解释 |
-E | 告诉编译器只进行预处理操作 |
-o | 把预处理的结果输出到指定文件 |
-S | 告诉编译器进行预处理和编译成汇编语言操作 |
-c | 生成目标文件 *.o |
C++的编译与C语言的编译几乎完全一致,只需要将gcc改成g++。
g++工具向下兼容gcc
四、GCC其他重要参数
- -g
编译带调试信息的可执行文件(gdb)

- -O[n]
优化源代码
- -l和-L
指定库文件|指定库文件路径
- -I
指定头文件搜索目录
- -Wall
打印警告信息
- -w
关闭警告信息
- -werror
把所有的告警信息转化为错误信息,并在告警发生时终止编译过程
- std=c++11
- -o
- -D
例子:
test.c
输出结果:

- -v
打印出编译器内部编译各过程的命令行信息和编译器的版本