文章目录
- 一.程序的翻译
- 二.gcc工具的使用
- 2.1gcc 文件名(直接编译)
- 2.2gcc -o 自定义 原文件(自定义生成可执行程序名称)
- 2.3./可执行文件
- 2.4gcc -E(程序运行到预处理后结束)
- 2.5gcc -S(程序运行到编译之后结束)
- 2.6gcc -i(程序运行到汇编之后结束)
- 2.7小结
- 三.链接的过程
- 3.1ldd命令
- 3.2语言级别的头文件
- 3.3语言对应的库
- 3.4动态库
- 3.5静态库
- 3.6Linux下的库
- 3.7库的总结
- 1.库的分类
- 2.库和链接
- 3.链接成功之后
- 4.空间问题
一.程序的翻译
gcc和g++都是一个编译器,gcc是用来编译C语言的,g++可以编译C语言也可以编译C++。
这个和之前学的vim工具一起可以实现在Linux上写C语言或者C++的代码。
g++和gcc类似,基本一样,接下来我主要围绕着gcc来讲。
在学gcc这个工具之前先来了解我们写的代码是如何变成一个可执行程序的,也就是程序的翻译过程。
- 预处理:在这一个过程,会将我们写的C代码进行头文件展开,条件编译,宏替换,去注释等。虽然比较复杂,但是预处理完之后,这个代码仍然是C语言代码。
- 编译:将C语言变成汇编语言。
- 汇编:将汇编语言变成可重定位目标二进制文件。这个文件是不可被执行的。一般这种文件都是后缀都是.obj。而且这一个步骤,只把我们自己写的代码进行翻译形成二进制文件。也可以说我们这个工程里有几个.c文件就会对应有几个.obj文件。
- 链接:将我们上一步得到的这些.obj文件和库文件进行合并,形成可执行程序。
二.gcc工具的使用
2.1gcc 文件名(直接编译)
gcc后面直接跟你要编译的.c文件就可以了:
gcc myfile.c
编译完之后,你所在的目录里就会自动生成一个a.out的可执行文件:
2.2gcc -o 自定义 原文件(自定义生成可执行程序名称)
gcc默认生成的可执行程序名称是a.out。但如果你希望自定义生成的文件名,可以用-o命令:
gcc -o myfile myfile.c
-o后面跟的就是你希望生成的文件名:
一定要注意-o后面要紧跟着自定义的文件名,所以-o myfile也可以放在其他位置:
gcc myfile.c -o myfile1
位置可以任意放,但是不要放在gcc前面。
2.3./可执行文件
gcc生成的可执行文件之后,可以在前面加上./来执行这个文件,这样的话,我们就可以得到我们代码执行的最终效果:
之前的三个可执行文件是都可以执行的。
2.4gcc -E(程序运行到预处理后结束)
gcc .c文件会帮你一次执行到链接然后结束。但是我们现在希望能一步一步的执行。所以gcc给我们提供了-E的指令:
-E:程序从现在开始进行程序的翻译,预处理做完就停下来
但是执行完这个指令后发现,它把预处理完之后的结果全部显示到显示器上,但是这样看的会很不舒服。所以我们在这个命令后面加点东西:
在指令后面加上-o 文件名这个命令可以上执行的结果放到这个文件里面。当然这个文件名你可以自己随便取,但是一般预处理执行后的文件后缀以.i结尾。
我们接下来看看这个.i文件和原来的.c文件有什么区别。
首先,大小就已经是天差地别了:
然后再看内部的代码:
发现一个10几行,而另一个有800多行。多出来的这么多行其实就是stdio.h文件展开的内容。接下来我们看主函数代码:
发现预处理之后,宏定义的被直接替换,注释全部被删掉,条件编译也被替换掉了。
2.5gcc -S(程序运行到编译之后结束)
-S:从现在开始进行程序的翻译,当编译做完,就停下来
这个命令的意思就是说,从myfile.c这个地方开始,运行到编译之后结束。编译完之后,会自动帮我们生成一个.s的文件。
当然我们直接从.i这个文件开始执行也是可以的:
2.6gcc -i(程序运行到汇编之后结束)
-i:程序从现在开始翻译,当汇编做完之后就停下来
这个命令的意思是从现在这里也就是myfile.s这个文件开始,汇编执行完之后结束,同样默认帮我们形成一个.o文件。这个二进制文件在Windows下是.obj文件,在Linux文件下是.o文件。
2.7小结
上面三个步骤已经把整个程序的前三步做完了,最后一步,也就是链接的部分,不用其他什么命令,可以直接gcc运行,也可以gcc执行.o文件:
gcc myfile.o -o myfile
gcc myfile.c -o myfile
这些类似的写法都是可以的。最终就得到了一个可执行文件。
通过上面那些步骤,对初学者来讲可能就有点昏头了,一个gcc工具,一下子多出来了这么多的指令。
巧记命令:
其实看目录2.4-2.6这三步,需要用到的指令连起来就是:ESc,这不就是键盘左上角那东西吗?只不过这里的S是大写的。以后要是忘了就到你键盘上瞄一眼。
三个步骤生成的文件类型连起来就是-iso。这是镜像文件的后缀名。记不住也没问题,多读两遍就熟悉了。
g++用到的命令和gcc差不多,这里就不在赘述了。
三.链接的过程
3.1ldd命令
在学习之前先学一个指令:ldd
ldd:显示出该文件都依赖哪些库。
接下来我们再来了解一个点:
我们为什么能在Linux上写c/c++的代码呢?因为Linux系统默认已经携带了语言级别的头文件和语言对应的库。
像我们写一个hello word。要用到printf这个函数,而printf函数,我们需要对应的头文件。
然后C语言本身也是一个库,像我们用到的while循环,for循环,int…这些都是在一个语言库里。
所以说要运行一个C语言代码首先要各种各样的头文件,语言所需要的库,还有一个能将代码转换成二进制的编译器。Linux中这些东西都有,所以我们能在Linux上写c/c++的代码。
3.2语言级别的头文件
Linux中C语言用到的头文件所在的位置一般在**/usr/include/**这个目录下
语言级别的头文件我们已经清楚了。那语言对应的库是什么呢?
3.3语言对应的库
在学习库之前要明白一件事:
在这些编译型语言,库一般分两种(库也是一个文件)。
1.Linux的静态库:libxxxx.a(一般以.a结尾)
2.Linux的动态库:libxxxx.so(一般以.so结尾)可能有的动态库后面还会跟一些各种各样的版本。
1.Windows的静态库:libxxxx.lib
2.Windows的动态库:libxxxx.dll
中间这些xxxx就是库对应的名字。
接下来我么在看一下刚才用ldd找到的那个可执行程序文件所需的库:
这里我们主要观察一下中间这个。myfile文件用到的一个库的位置就是在/lib64/libc.so.6这个地方:
而libc-2.17.so就是myfile这个文件所依赖的库。如果我们把前缀后缀去掉,剩下的就是c-2.17,说明myfile是用C语言来写的。
3.4动态库
库你目前就简单认为是一个装有很多函数的大箱子就行,这些函数都是某些人帮你写好的。
那什么是动态库呢?在解释之前,我把动态库变成你生活中的例子来解释:
假如你是一名准高一的学生,你希望在暑假的时候好好熟悉一下即将要上的高中附件有什么新奇的东西,比如说-- 网吧。你很想知道你们学校边上的网吧在哪里,但是你又有点懒,不想自己动身去看,于是你就去找了一个曾经在这个学校上过学的远方表哥,然后他就把网吧的地址告诉你,你也认认真真的记下来了。
紧接着,你觉得要上高中了,总不能一直去网吧。所以你就自己制定了高一每天的任务清单:
- 早上6点起床背单词
- 上课
- 吃饭,午睡
- 上课
- 下课写作业
- 吃饭
- 上网!
- 睡觉
好,任务清单做好了,初三的暑假也结束了。所以你高高兴兴去高中上学,并且认认真真的执行暑假中指定的任务。清单中除了上网,其它的事情都可以在学校中完成。所以你要上网,只能跑到你远方表哥跟你说的地址去上网,进入网吧后兴冲冲的开了一台电脑并玩了起来,然后玩完之后回学校睡觉。一天就这么愉快的过去了。
在上面的小故事之中:
- 你就代表程序。
- 你的任务清单就是你写的代码。
- 你的远房表哥告诉你地址并且记住的过程就叫做动态链接。
- 你上的高中就是所谓的内存
- 你的远房表哥就相当于你的编译器。
- 而网吧就代表今天所要理解的动态库。
- 你去高中上学的过程就是程序导入到内存的过程。
- 你跑去上网玩游戏的过程就是调用库函数。
接下来我们在谈谈我们的大表哥,就是你这个表哥呀,他曾经是这个学校的学生会主席,很多人都认得他,所以和你同级的学生也认得这个表哥,所以这个网吧里不止有你这一个人去,这个学校里的很多人都在去,所以这个网吧不是私有网吧,而是共享网吧。同理动态库也等价于共享库。
想必上高一的孩子基本上都是未成年吧,我记得未成年好像不让去网吧,我为了让祖国的花朵健康成长,于是我把这个网吧举报了,警察过来罚款,贴封条。好了,现在就都没人玩了。所以说,如果你不小心把你电脑中库给删掉了,你写的绝大部分指令和代码就都运行不了了。
3.5静态库
刚才的网吧被警察封了,你很难受,哭着找到了你的爸爸,当然,你的爸爸也很爽快,当场就同意了。后来你父亲找到了当初那家网吧的老板,觉得他家的电脑配置很不错,所以你父亲就按着这个配置给你买了一个。
而这个按网吧电脑配置给你买电脑的过程就叫做静态链接:将动态库中的代码拷贝一份到你的程序中。
3.6Linux下的库
在Linux下默认使用的是动态库和动态链接,我们可以用指令来查看最开始生成的可执行文件的具体信息:
会发现这里写的就是动态链接(使用分享库)。
但是我希望我现在写的程序是动态链接,该怎么做呢?
方法很简单在用gcc指令后加上一个-static就行:
接下来我们在直观上观察一下这两种方式得到的可执行程序:
可以看到静态链接得到的可执行程序内存要大得多,这里好像有100倍的样子。
一般你的服务器或者系统,都是默认只有动态库,如果这时候你进行静态链接,会出错的
但是你可以用指令下载一个:
C语言静态库:
sudo yum install -y glibc-static
C++的静态库也可以下:
sudo yum install -y libstdc++-static
3.7库的总结
1.库的分类
动态库:专门让编译器对用户的程序进行动态链接的。
静态库:专门让编译器对用户的程序进行静态链接的。
2.库和链接
动态库和动态链接:链接的时候如果是动态链接,找到动态库,拷贝动态库中我所需要的代码的地址到我自己可执行程序中的相关位置。
静态库和静态链接:链接的时候如果是静态链接,找到静态库,拷贝静态库中我所需要的代码到我自己可执行程序中。
3.链接成功之后
静态库:链接成功后,我们的程序不需要依赖任何库,自己可以独立运行。
动态库:连接成功后,还是要依赖动态库,一旦动态库缺失,我们的程序将无法成功运行。
4.空间问题
静态库:虽然在链接成功后直接可以脱离库,独立运行,但是这样做你的程序必然会因为静态库的到来变的很大,如果内存里不止有一个程序呢?那必然会造成空间的极大浪费。
动态库:虽然在链接成功后还要依赖库,但是程序内部只有地址,非常的节省空间。