以gcc编译
以g++编译,但是此时会发现没有g++这个指令,所有需要安装它,安装指令
yum install gcc gcc-c++
gcc和g++都会形成可执行文件a.out
gcc只能编译c语言代码,g++能编译c/c++
以c程序为例,来看看它从一个文本类的c程序编译成计算机可以认识的二进制程序它需要经过四个阶段
预处理
编译
汇编
连接
每个阶段要做什么?
预处理
预处理阶段会做
1.去注释
2.头文件展开
3.条件编译
4.宏的替换
编写一个c程序,其中有宏、头文件、注释
而gcc它预处理阶段所需的选项是-E
-E后面跟的是编写的文件,然后-o是生成目标文件,可以自己指定生成文件名
然后再打开文件将这两个文件一对比
预处理之后mycode这个文件里面的内容较于mycode.c文件多了太多内容了
从开始行一直往下翻,直到int main,它多了这些内容都是从头文件中拷贝过来的,而这个行为是头文件的展开
它多出了这么多内容是从头文件中拷贝过来的,那么这个头文件又是从哪来,其实在你安装编写c/c++或者其它语言的环境时,不仅仅是安装了软件,还将其所需的头文件库文件等内容也一并安装了,头文件头文件他也是文件对吧!来看看头文件存在系统哪里
一般开发所需的头文件它是在/usr/include/
这个路径下
这个路径是Linux下gcc/g++它的头文件的搜索路径
如打开stdio.h这个头文件
它里面有很多内容
所有我们在安装如vs2022之类的开发环境之外,还安装了对应的开发包!同步也在下载了c/c++的头文件
而其中宏定义的M,经过预处理之后进行了值替换
注释也去掉了
条件编译
它是以宏的方式定义DEBUG,它是如果存在这个,那么就输出 printf(“hello\n”);
没有保留printf(“xiao\n”);,他这是选择!
在预处理之后编译器继续运行形成汇编!这个阶段叫做编译
编译
编译会将代码形成汇编
gcc -S mycode.c -o mycode.s
汇编,是 -S
选项,后面跟源文件,-o 汇编成目标文件,一般以.s为后缀
vim打开mycode.s文件,会发现里面都是汇编代码
形成汇编代码之后再经过汇编阶段形成机器可以识别的二进制码
汇编
它汇编阶段的选项是-c
演示汇编阶段 gcc -c mycode.s -o mycode.o
当以vim打开这个文件,全是乱码,这是因为它是一个文本编辑器,要以专门看二进制文件的。
以od这个工具查看
汇编之后再经过连接形成可执行文件。
连接
直接gcc编译不用再跟选项,gcc mycode.i -o mytest
它会形成可执行文件
-o后面紧跟着你要形成的文件名,自定义的!如果不加,那么它会形成a,out
-E:预处理!对程序进行翻译,将预处理工作做完就停下来,再执行就是编译了
-S:编译!将c语言代码翻译成汇编代码,编译工作做完之后就停下来,再执行就是汇编
-c:汇编!将汇编代码翻译成机器可识别的二进制码,它生成可重定向的二进制文件
连接:将二进制文件与库进行链接形成可执行程序
链接它的库是啥作用?这个库给我们提供方法,他其实就是c语言的标准库,那么它在哪存在?
存在:/usr/lib64之下,
此时只看见有动态库,等会安装静态库
静态库安装
安装C语言静态库
yum -y install glibc-static
安装c++静态库
yum -y install libstdc++-static
c语言的标准库本质上是一个文件,库分两种,Linux下:动态库(.so),静态库(.a)
windows:动态库(.dll),静态库(.lib)
而库一般有自己的命名规则的:libname.so.xxx
有了头文件有了库文件,它方法的实现也是再库中实现,它是把源文件经过一定的翻译,然后打包,只提供一个文件,这样也可以达到隐藏文件的目的
头文件提供方法的声明,库文件提供方法的实现,加上写的代码就成为一个软件了
gcc自动去找c语言库中找与.o文件链接形成可执行文件!那它们是如何链接的?
两种链接方案:动态链接;静态链接!
动态链接:就相当于高中,学校旁边哪哪哪有一个网吧,然后学生周天去上网,学生在执行着各种活动,然后忽然想去上网,它他在学校是上不了的,因为他没有电脑,所有他跑去网吧上网,打游戏!这个网吧就相当于动态库,每次想上网都要去网吧登机才行,这种链接方式就叫做动态链接!而网吧上网不可能只有你一个人吧,有很多人去,他是共享的,动态库是共享的,这所学校的所有学生要上网都去这个网吧去!
而当这个网吧倒闭之后,这所学校的学生就不能去上网了,真惨啊!
所有动态库不能缺失,一旦一个动态库缺失,可能很多程序都无法运行,不然会让很多程序都无法跑起来!
查看一个可执行程序依赖的动态库
ldd指令
如果删掉了这个动态库文件他就跑不起来了!不要删,不然可能不止他一个程序跑不起来,可能会很多都跑不起来,因为Linux很多指令都是用c语言实现的,如果你删了,可能很多指令也不能执行噢!
静态链接:将库中的方法拷贝到自己程序中,他每次要用的时候不用再去库中,自己就能实现,这样的方式就叫做静态链接!如果有一天他的方法所在库不在了他还是可以照样运行!它不再依赖于这个库了,它将所有方法都拷贝到这个程序中!
动态链接是将方法实现在哪里拷贝到程序中,每次要连接时都要去动态库中,静态连接是将方法实现拷贝到程序中,每次要时不必去静态库中连接!但是静态连接会使程序变大,因为它拷贝了更多的东西!
在Linux中默认采用的就是动态链接!使用动态库!
而如果当想要使用静态链接要在编译时要加-static选项。静态链接是需要手动添加选项的。此时也就要求系统提供静态库。
而静态链接可以发现它的体积远大于动态链接方式!
如果没有静态库是不能使用静态链接方式的,但是如果没有动态库,只有静态库,并且能够找到,这是可以的,就算没有使用static也可以因为gcc默认链接是动态如果没有会用静态链接!其实使用static是改变链接优先级了,所以啊,一个可执行程序,为其提供的库可能不止一个偶,可能动态静态都有!
来动静态库比一比
动态vs静态
动态库是共享库,可以有效的节省资源(磁盘、网络、内存空间)缺点:动态库不可缺失,一旦缺失导致很多程序无法运行
静态库不依赖库,程序可以独立运行。缺点:占用体积大,比较消耗资源!
debug和release
在vs下程序有两种开发方式debug和release方式,平时用的就是debug方式,当代码需要提测测试时要将其以release的方式发布!测试发布的版本和用户拿到的时一样的,默认发布为release,而以debug形成的可执行程序可以被追踪,为何?因为它添加了可调试信息
而由于它添加了调试信息,它形成的可执行程序的体积又要比一般程序的大
还说一个选项 -g选项,它会将软件以debug方式发布,
那么如何去看是否是debug方式发布呢,可以使用readelf -S来查看
它会以二进制方式查看,然后可以grep debug过滤
这些也就是添加的debug信息!
g++也是一样的,就不再演示了!
就到这了!