前言:
在上一篇,我们学习了关于文本编辑器 vim 的全部知识,今天给大家带来的是关于Linux编译器—gcc/使用的详细介绍。
本文目录
(一)温习程序的产生的过程
1、前言
2、程序的产生过程
3、初步认识 gcc
a) gcc的基本概念
b)gcc的基本特点
4、使用方法
(二)逐过程讲解
1、 预处理
2、 编译
3、 汇编
4、 链接
5、巧记选项
(三)动静态库的理解
1、前言摘要
2、ldd 指令
3、动静态库的理解
a)概念
b)区别
c)实例演示
d)总结动静态库的优缺点
(四)总结
通过之前的学习,我们可以知道在 Linux 下编写C\CPP 程序时,在完成 .C 或 .CPP 文件的编写后,我们通常直接 gcc 或 g++ 后接文件名,就可以在当前文件夹下生成 a.out 可执行文件, 之后输入 ./a.out 即可执行该二进制可执行文件。
但实际上C语言程序从编写到运行,这期间的经历并不是这么简单,接下来我就带领大家对其探索一番,这期间具体有哪几个步骤?
从之前的知识来说,我们应该都知道程序的翻译经过几个阶段。我们会历经三个步骤,分别是:【预处理阶段】——>【编译阶段】——>【链接阶段】。但是如果我们分的更细一点,其实我们可以分成四个步骤:
通常 gcc 命令后面不加选项的话,就会默认执行 预处理、编译、汇编、链接所有步骤,若程序没有错误的话,我们就可以得到一个可执行文件,默认为 a.out, 也就是上述我代码中出现的。
有了上述的铺垫之后,接下来我们讲讲什么是 gcc吧!!先让大家有了认识,以便我们后序的深入学习。
gcc 是一个常用的 C 语言编译器,可以将源代码转换成可执行程序。 使用 gcc 编译器需要以下步骤:
格式为:
gcc <源代码文件名>.c -o <输出文件名><源代码文件名><输出文件名>
例如,编译名为 的 C 语言源代码文件,并将其输出到名为 的可执行文件中,可以使用以下命令:hello.c
hello
gcc hello.c -o hello
//加入-o选项的意义在于你可以指定输出二进制文件的名字
有了上述的前情铺垫之后,接下来我们具体的讲讲各个阶段到底是是怎么样的!!
首先第一步就是预处理阶段,在这个阶段主要主要执行的包括以下四个步奏:
举例说明:
其中预处理阶段是把代码中的【#】开头的命令进行相应的处理,例如:
gcc执行指令
gcc -E test.c -o test.i
1 #include
2 #define MAX 1000
3
4 int main()
5 {
6
7 printf("hello world\n");
8
9
10 int m = MAX;
11 printf("%d\n",m);
12
13 printf("hello world\n");
14
15 // printf("hello world\n");
16 // printf("hello world\n");
17 // printf("hello world\n");
18 // printf("hello world\n");
19 // printf("hello world\n");
20 // printf("hello world\n");
21 // printf("hello world\n");
22
23
24
25 return 0;
26 }
经过 命令之后就变成了这样
选项
预处理阶段过后紧接着就是编译阶段。这个阶段处理的就是c语言的汇编语言,它主要处理的包括以下:
注意:
gcc执行指令
gcc -S test.i -o test.s
其实【gcc】在执行编译命令的时候会带上预处理,然后不保存过渡用的预处理出来的【.i】文件,所以编译时候的输入还是你写的【.c】文件,如果想看一看预处理结果的话才用【-E】指令;
其次如果我们直接用原始【.c】文件来编译一下也可以,用刚生成的【.i】文件编译也是可以的,命令是【gcc -S test.i -o test.s】(我这里默认的是从上次结束的地方继续执行)
最终结果是一个汇编程序的文件,注意这里输出的仍然是一个文本文件。
选项:
编译阶段过了之后,紧接着就是汇编的执行阶段。在这个阶段,它做的主要有以下的事情:
将汇编指令转换为二进制文件
形成符号表
gcc执行指令
gcc -c test.s -o test.o
汇编就是把编译出来的汇编文件打包成一个二进制文件,里面存的都是机器指令.gcc的命令是【gcc -c test.s -o test.o
】, 得到的结果是个【.o
】文件,这个文件是不能用人类语言解读的,打开发现是一堆乱码
此时当我们想来试着执行一下这个目标文件时,不过发现没有【x】可执行的权限,于是使用chmod
做一个提权的操作。
但是系统却说【cannot execute binary file
】因为这是一个二进制文件,对于二进制文件来说是不可以被执行的。
选项:
最后,即是链接操作了,在这一步主要做的事是:
gcc执行指令
gcc test.o -o test
检查刚才的【.o】文件,查看它引用的其他【.o】文件,比方说【printf】函数就是C语言的库函数,她在一个单独的【printf.o】文件里,这个文件在 gcc 的目录里面,和我们现在创建的工程没有关系,所以看不见;
但是它会去库中找这个文件,所以链接就是找到它,然后把他们集成到一个可执行程序里
最后,我们打印一下最后的文件,看是否能够正常的运行并且输出对应的结果:
⌨️命令选项 :【-E】 【-S】 【-c】——>键盘上左上角的键(注意 s 要大写)
⌨️文件后缀 : 【.i】 【.s】 【.o】——>iso为镜像文件的后缀
文件后缀:
命令选项:
此时,不知道大家知不知道我们为什么能够在【Linux】在进行C、C++代码的编写和编译呢?
首先,我们先编写【.Cpp】程序试试看在【Linux】上是否能够运行!
运行结果如下:
上述我们可以发现,对于【.cpp】程序一样是可以的。那么到底是为什么呢?是怎么实现的呢?
我们先来看看系统中的头文件所在目录,然后就可以发现我们熟悉的头文件名【stdio.h】等
头文件是告诉我们使用的方法,通过头文件的方式把方式告诉我们,其次也在告诉编译器,头文件是否有,只要有头文件就有源文件。
ldd本身不是一个程序,而仅是一个shell脚本:ldd可以列出一个程序所需要得动态链接库
我们可以用which命令找到ldd的位置:
格式:
ldd(选项)(参数)
紧接着我们就可以去看看刚才【g++】之后最终链接后形成的【a.out
】这个可执行程序都依赖了哪些库。
注意:
在 ldd 命令打印的结果中:
“=>” :左边的表示该程序需要连接的共享库之 so 名称;
右边表示由 Linux 的共享库系统找到的对应的共享库在文件系统中的具体位置。
因此,在此就解答了上述的问题为什么可以在【linux】下编写代码了!!!
此时,有衍生出来了一个问题——>那就是大家知道我们平时写代码的【vs2022】啊还是【vs219】或者其他的,当我们刚开始安装它的时候,实际上帮我们完成的最重要的工作是什么吗?
紧接着,我们在【linux】下是不是纯手工的方式进行操作啊,用的全是指令,那么这些指令怎么来的呢?
我举几个例子带大家见识见识:
综上所述:
我们可以看出在【linux】下,不管是 指令、工具、还是程序 等都是通过C语言写出来的!!!
首先,在学习之前,我们肯定地需要知道什么叫做动静态库。因此,第一步我们先认识静动态库:
静态库:
动态库:
1、 代码被载入的时刻不同
2、大小与共享的差异
2、程序编译的差异
在常用的指令中我们有说到过【file
】指令,这个指令的作用是可以用来查看一个文件的类型,接下来我们就去瞧瞧这个动态的可执行文件
那这时就有小伙伴要问了?那我们如何实现静态链接呢? 其实很简单,只需在最后加上 【-static】即可。
但是如果大家没有安装静态库,此时你在你在执行以下代码的话就会报错(云服务器默认使用的是动态库)
(sudo) yum install -y glibc-static
(sudo) yum -y install libstdc++-static
演示如下:
所以大家知道为什么云服务器默认是安装的动态库了吧!!!
静态库
动态库
有关动静态库的更多知识,我们将在后面进行补充讲解!
到此,本文的内容便讲解完毕!最后,我们对本期内容做个小结!!!
以上便是本文的全部内容了,感谢大家的支持!!