一.初识gcc,g++
gcc是GCC中的GUN C Compiler(C 编译器)
g++是GCC中的GUN C++ Compiler(C++编译器)
就本质而言,gcc和g++并不是编译器,也不是编译器的集合,它们只是一种驱动器,根据参数中要编译的文件的类型,调用对应的GUN编译器而已.所以,更准确的说法是:gcc调用了C compiler,而g++调用了C++ compiler
二.
1.1.编译器自举
自举是指使用某个版本的编译器来编译和构建该编译器的过程。在Golang的自举过程中,我们需要一个已经使用其他语言(如C语言)编写的初始版本的Golang编译器,然后使用该初始版本编译和生成另一个版本的编译器。使用新生成的编译器,我们可以进一步编译和构建更高版本的编译器。重复这个过程,我们最终可以生成一个完全由Golang编写的Golang编译器,从而达到自举的目标。
链接:https://www.zhihu.com/question/601044288/answer/3101520643
1.2.程序的翻译过程
1.2.1预处理:
预处理是编译过程的第一个阶段,由预处理器完成。在这个阶段,编译器首先处理源代码中的预处理指令,比如宏定义、条件编译和包含文件等。预处理器将根据这些指令修改源代码,生成一个预处理后的文件,通常扩展名为.i
。
gcc -E:开始程序的翻译,等预处理做完就停止
1.2.2编译:
编译阶段是将预处理后的文件转换成目标文件的过程。编译器将预处理后的代码进行语法分析、语义分析、优化等操作,生成汇编代码。每个源文件对应一个目标文件,扩展名为.o
或.obj
。
gcc -S:开始程序的翻译,等编译做完就停止
1.2.3.汇编:
汇编阶段是将目标文件转换成机器码的过程。汇编器将目标文件中的汇编代码转换成机器码,生成一个或多个可重定位的目标文件。
gcc -c:开始程序的翻译,等汇编做完就停止
1.2.4.链接:
链接阶段是将可重定位的目标文件转换成可执行文件的过程。链接器将多个目标文件中的代码和数据合并成一个可执行文件。
代码+头文件+库=可执行程序
开发环境安装实质上就是安装下载并拷贝头文件和库文件到开发环境的特定路径下,前提是一定能被编译器自己找到。
1.3.动静态库
1.3.1.动态库: 是c/c++或者其他第三方提供的所有方法的集合,被所有的程序以链接的方式关联起来
动态链接:指在运行期间按名称将库复制到可执行文件中的过程。这意味着操作系统只在程序运行时将必要的文件(共享库)加载到内存中。
优点:形成的可执行程序体积比较小,比较节省资源
缺点:稍慢一些,强依赖动态库
1.3.2.静态库: 是c/c++或者其他第三方提供的所有方法的集合,被所有的程序以拷贝的方式,将需要的代码,拷贝到自己的可执行程序中
静态链接:指通过链接器将你程序中所有必要的库直接复制到可执行程序中。它发生在编译阶段的最后。
优点:无视库,可以独立运行
缺点:体积太大,浪费资源
1.4.自动化构建代码
1.4.1.make:一个命令,用类似于批处理的方式—通过调用makefile文件中用户指定的命令来进行编译和链接的。(make会默认执行从上到下第一个文件)
1.4.2.Makefile:是一个在当前目录下存在的一个具有特定格式的文本文件。
Makefile里主要包含了五个东西:显式规则、隐晦规则、变量定义、文件指示和注释,
- 显式规则说明了,如何生成一个或多个目标文件。
- make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写makefile,比如源文件与目标文件之间的时间关系判断之类
- 在makefile中可以定义变量,当makefile被执行时,其中的变量都会被扩展到相应的引用位置上,通常使用 $(var) 表示引用变量
- 文件指示。包含在一个makefile中引用另一个makefile,类似C语言中的include;
现实中,关系+方法==描述一件事的原因做法,能达到我们的目的
1.4.3.清理可执行文件 clean
1.4.4伪目标 .PHONY:
makefile中的伪对象表示对象名称并不代表真正的文件名,与实际存在的同名文件没有相互关系,因此伪对象不管同名目标文件是否存在都会执行对应的生成指令。伪对象的作用有两个,1. 使目标对象无论如何都要重新生成。2. 并不生成目标文件,而是为了执行一些指令。
注:文件的ACM时间
使用指令stat+文件名,显示文件详细信息。
文件=内容+属性
故对于一个文件,有以下几种重要时间:
Access:文件最近被访问的时间(访问)
Modify : 文件内容最近被修改的时间(修改)
Change : 文件属性最近被修改的时间(改变)(一般而言,对文件做了相关操作,其acm时间也会相应改变。但经观察,accesstime不是每次一访问便修改的。原因:文件放在磁盘里,对于文件的访问也是对磁盘的访问,磁盘速度较慢;linux中充满大量的访问磁盘的io操作,若更改access时间太多,变相的减慢了系统效率。
使用make指令后发现,在我们编译代码时,make和Makefile总是不让我们重新编译我们的代码。
其原因是会通过时间对比,可以做到不让有些代码进行重新编译----->
第一次编译形成可执行文件时,一定是先有源文件,才有bin文件,故源文件的修改时间<bin文件的修改时间。
第二/n次时,队员文件做任何修改的时候,都会导致 源文件的修改时间>bin文件的修改时间
1.5.进度条小程序
1.5.1.倒计时小程序
注:(1)缓冲区:C/C++语言,会针对标准输出,给我们提供默认的缓冲区
(2)回车换行:
回车 \r 本义是光标重新回到本行开头。
换行 \n 本义是光标往下一行(不一定到下一行行首)
在不同的操作系统这两个字符表现不同,比如在WIN系统下,这两个字符就是表现的本义;在UNIX类系统,换行\n就表现为光标下一行并回到行首,在MAC上,\r就表现为回到本行开头并往下一行。至于ENTER键的定义是与操作系统有关的,通常用的Enter是两个加起来。
1 #include <stdio.h>
2 #include<unistd.h>
3 int main()
4 {
5 int cnt=10;
6 while(cnt>=0)
7 {
8 printf("%-2d\r",cnt);
9 fflush(stdout);
10 cnt--;
11 sleep(1);
12 }
13 return 0;
14 }
运行结果:
1.5.2.进度条(简单原理版本)
5 #define SIZE 101 数组中除了字符还有末尾'\0'
6 #define MAX_RATE 100
7 #define STYLE '#' //自定义进度条风格
8 #define STIME 1000*40
9
10 const char *str="|/-\\"; //字符数组模拟旋转光标
11
12 void process()
13 {
14 int rate=0;
15 char bar[SIZE];
16 memset(bar,'\0',sizeof(bar));
17 int num=strlen(str);
18
19 while(rate <= MAX_RATE)
20 {
21 printf("[%-100s][%d%%][%c]\r",bar,rate,str[rate%num]);
22 fflush(stdout);
23 usleep(STIME);
24 bar[rate++]=STYLE;
25 }
26 printf("\n");
27 }
1.5.3.进度条