Linux 编译器 gcc/g++

举报
ARMCSKGT 发表于 2023/05/28 13:51:18 2023/05/28
【摘要】 介绍gcc和g++的基本使用!


本文已收录至《Linux知识与编程》专栏!
作者:ARMCSKGT
演示环境:CentOS 7 

   



前言

在Windows环境下,我们我们使用VS编译器可以写代码然后运行编译代码所成的程序,但在Linux系统下,我们写的C/C++代码需要通过gcc(C语言)和g++(C++语言)编译器才能生成可执行程序,所以学习gcc和g++是非常重要的!


正文

在实际的使用中,单纯的编译执行C和C++文件gcc和g++操作几乎相同,但是内部工作原理是截然不同的!所以在后面的讲解中会以gcc为例进行讲解,g++操作与之相同!


如果您在使用时系统报错:bash: gcc(或g++): command not found,这是因为你的Linux系统没有安装gcc或g++导致的,使用命令:

yum -y install gcc //安装gcc
yum -y install g++ //安装g++

一般Linux系统是安装了gcc的,但g++需要手动安装!


gcc/g++常用命令


我们在使用中,如果想利用对应文件生成可执行程序,命令是:

gcc [-选项] [.c文件]
g++ [-选项] [.cpp文件]

如果不加(除o)的其他选项,那么默认直接生成可执行程序,程序名为a.out,我们输入命令 ./a.out 就可以执行这个程序!


自定义可执行程序名命令-o

命令:

gcc [.c文件] -o [自定义名称] //建议写法
gcc -o [自定义名称] [.c文件] //这种写法也是可以的,但是不建议

这里需要注意的是,-o选项后面紧跟的必须是自定义名称,可以想象:-o [自定义名称] 是固定组合,不能颠倒顺序乱写

g++也可以通过-o选项生成自定义名称的可执行程序!


我们都知道源文件变成可执行程序会经过四个阶段:预处理->编译->汇编->链接库,gcc/g++编译时如果不加选项是直接执行这四步,如果我们想看其中一步执行后的文件,那么就需要对应的选项。


预处理指令-E

指令:

gcc -E [.c文件] -o [文件名].i

预处理又称预编译,预处理后的文件其后缀我们默认是 .i ,而且在这里我们如果想获得预处理后的代码文件还需要指定一个文件名,如果不使用-o指定文件名,gcc会将预处理后的代码输出到屏幕上,只有指定文件名才能保存为文件!

 

代码的预处理会将头文件展开,替换宏,删除注释并执行条件编译等操作,这样才能生成一个纯C语言的代码文本方便后面继续转换!

使用vim打开后里面都是预处理后的代码 

这里我们使用-E选项是让编译器执行完预处理就停下! 


编译指令-S

指令:

gcc -S [.c文件/.i预处理文件] //默认生成的文件与编译前的文件名相同但是后缀为.s
gcc -S [.c文件/.i预处理文件] -o [文件名].s //指定生成汇编代码的文件名

这里如果我们不使用-o选项编译器会生成与被编译文件名一样的文件但后缀为.s,且这里既可以对.c代码文件编译,也可以对预处理文件.i进行编译,只不过对.c文件进行编译会先执行预处理然后再执行编译,执行完编译就停下,而预处理文件则是直接进行编译然后停止!

 

编译会对预处理代码进行语法词法并和语义分析,并进行符号汇总等,然后转换为汇编代码。

vim打开编译的文件里面是汇编代码和一些符号标记 

汇编指令-c

指令:

gcc -c [.c文件/.i预处理文件/.s编译文件] //默认生成与被执行文件的文件名相同后缀为.o的二进制文件
gcc -c [.c文件/.i预处理文件/.s编译文件] -o [文件名].o

这里如果我们不使用-o选项编译器会生成与被编译文件名一样的文件但后缀为.o,且这里既可以对.c代码文件,.i代码文件和.s汇编代码文件进行汇编,只不过对.c文件进行编译会先执行预处理然和编译,然后执行汇编后就停下;.i文件会先执行编译再执行汇编就停下,.s文件则直接进行汇编然后停下!

 

汇编是将汇编代码转换为二进制汇编文件且生成符号表,这里的二进制文件通过file指令查看是elf格式,通过vim打开会显示一片乱码!

 我们如果想查看这个文件,需要通过指令:

readelf -a [二进制文件.o]

 有需要的小伙伴如果缺失这个功能可以通过yum下载!指令:

yum -y install readelf

链接指令gcc

指令:

gcc [.c/.i/.s/.o文件] //默认生成a.out可执行程序(可使用-o自定义名称)

链接是形成程序的最后一步,如果前面缺少一步就会先执行没有进行的步骤!

链接会进行合并段表,将符号表进行合并和重定位等;然后会将程序与运行所需要的各种函数和库函数链接起来(编译器默认动态链接),生成可执行程序的格式是elf,也可以通过readelf指令查看!


命令巧记口诀

指令 ESc (键盘上的退出键),文件后缀 iso (镜像文件格式)


 链接库


我们都知道,每种语言都有属于自己的库,比如C语言的stdio标准库等,C++有iostream库,当程序在在运行中调用库函数时就会通过地址去库中找这个函数进行调用!在Linux系统中,标准库在 /usr/include/ 目录下,在这个目录下,是Linux系统的各种C语言动态库,除了动态库的概念外,还有静态库的概念,我们慢慢介绍!

Linux系统下的各种库 

库文件格式为:lib文件名.a/so,识别时去掉lib和后缀就是文件名!

动态库的文件格式为:lib文件名.so

静态库的文件格式为:lib文件名.a

 

在Linux系统中,指令也是可执行程序都是C语言写的依赖库!


动态库-动态链接

动态库又称共享库,动态库是动态链接的库,如果程序中有该库的函数和引用则会在调用位置留下一个链接,程序运行调用该函数时就会通过这个链接找到对应的库函数并执行!这样动态库只需要存一份代码就可以实现多个程序的调用!


链接就是将代码中使用的库函数与对应的库链接(将调用的库函数的文件地址拷贝到文件中)。

动态库一旦被删掉,那么所有依赖该库的程序就无法执行了;动态链接只是拷贝库的地址,执行时需要跳转到库中执行。


在Linux系统下gcc和g++链接是默认动态链接库的,如果我们想查看文件的链接方式,指令为:

ldd [文件/程序]  //查看程序链接库方式
打开后会显示各种链接状态且可以看到动态链接的文件后缀都是.so 
通过file指令还可以查看可执行程序的链接情况! 

 这也说明Linux是默认动态链接的!动态链接的好处在于编译出来的程序体积小,但是跨平台能力差!


静态库-静态链接

静态库采用静态链接的方式,静态链接与动态链接不同之处在于,动态库在调用库函数时根据地址去库中寻找并调用,而静态链接则是将调用的库函数拷贝到自己的代码文件中,相当于本地存储,后续直接执行本地代码文件,不依赖任何动态库!

如果需要静态库编译代码,指令是:

gcc [-选项] [.c文件] -static

可以在预处理-编译-汇编-链接这四个阶段选择静态链接,因为链接是最后一步!

Linux的静态库需要手动安装,指令是:

yum -y install glibc-static //下载静态库

 ldd指令显示文件没有链接任何库!file指令显示可执行程序是静态链接!

 而且静态库链接因为将库代码拷贝到了本地文件,其文件体积将会变得非常大!所以Linux中默认动态链接的方式!


动静态库对比

区别 动态库 静态库
库函数调用方式 通过链接去库中调用 在本地代码中调用
跨平台性与依赖性 需要依赖库运行,跨平台性差 不需要依赖库,跨平台性良好
空间占用 空间占用小 空间占用大
加载速度 需要根据链接去找库函数然后执行 直接执行本地库函数代码
优点

可以实现不同进程间的资源共享,对于函数的升级只需要替换动态库文件,不需要重新编译程序,可以控制是否加载动态库,不调用函数时就不加载

所需函数直接拷贝至程序中,运行速度快程序运行无需依赖库,便于移植和跨平台 

缺点

需要调用函数,加载速度较慢,程序运行需要依赖动态库

对于函数的升级,需要重新进行编译同一份代码可能出现重复拷贝的情况,浪费空间


其他指令


声明与定义分离的编译指令

gcc [-选项] [头文件.h] [实现代码.c] [主函数.c]

声明与定义分离,只需要将程序的所有相关文件列入gcc中,然后正常编译即可!


C99标准编译指令

gcc [-选项] [.c文件] -std=c99 //以C99标准编译代码

当我们想要C99标准语法时可以使用该指令编译!


查看可执行程序的反汇编

objdump -S [可执行程序]

如果我们需要通过反汇编了解程序的运行细节可以使用该指令!


gcc和g++的联系与区别


gcc和g++都是GNU(一个组织)的编译器。

 
1、对于.c后缀的文件,gcc把它当做是C程序;g++当做是C++程序;

2、对于.cpp后缀的文件,gcc和g++都会当做c++程序。

3、编译阶段,g++会调用gcc;

4、连接阶段,通常会用g++来完成,这是因为gcc命令不能自动和c++程序使用的库连接。


 最后

Linux编译器gcc/g++的介绍到这里就结束了,相信学完的老铁肯定想动手写两个程序吧?gcc和g++如此强大的功能来自于GNU组织的开发,让我们可以在Linux上看到代码的底层知识!本节也介绍了动态库和静态库的区别和优缺点,相信大家以后能对库进行合理利用,开发出好的作品!

本次Linux编译器gcc/g++的基本知识就介绍到这里啦,希望能够尽可能帮助到大家。

如果文章中有瑕疵,还请各位大佬细心点评和留言,我将立即修补错误,谢谢!

 🌟其他文章阅读推荐🌟

Linux基础指令

Linux权限的基本知识

Linux编辑器vim

🌹欢迎读者多多浏览多多支持!🌹

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。