当前位置: 首页 > news >正文

Linux环境基础开发工具->gcc/g++

引入:gcc/g++是什么?

在上篇博客我们知道,vim是一个编辑器,vim负责的是代码的编辑;而gcc/g++是一个编译器,负责的就是代码的编译!gcc负责C语言代码的编译,而g++负责c++代码的编译!

既然是编译,那就要先看这个链接一下编译器的工作分为哪几个步骤:编译链接的过程发生了什么?_编译链接 发生了什么-CSDN博客

注:本篇博客着重讲gcc,因为g++和gcc类似,不再赘述

一:快速使用gcc和g++

现在有一个.c文件,其内容如下:

我们对其进行gcc编译,生成了a.out:

对其进行执行:

以上就是使用gcc,非常的简单!

用起来非常简单,但其中的内容其实很多,只是我们gcc指令直接一步到位了,gcc是一个编译器,博主在此篇博客中介绍过编译的整个过程:编译链接的过程发生了什么?_编译链接 发生了什么-CSDN博客

总的来说在执行编译的时候一般有以下四个步骤


1)预处理(头文件展开、去注释、宏替换、条件编译)。
2)编译(C代码翻译成汇编语言)。
3)汇编(汇编代码转为二进制目标代码)。
4)链接(将汇编过程产生的二进制代码进行链接)。

每步对应的工作如下:

 

而gcc直接从一个.c文件 到了可执行文件,上面的这四步其隐式的执行了,所以我们要结合gcc的选项才能够才不同的时期停下来

二:gcc的选项

须知:

-o:将处理结果输出到指定文件,该选项后需紧跟输出文件名;所以-o也是gcc的选项,一般放在两个文件之中!

1:gcc -E(预处理)

用法:

gcc -E code.c -o code.i

解释:从现在开始对code.c文件进行翻译,当对code.c文件做完预处理工作的时候,就停下来,此时生成的文件我把他命名为code.i 。

如图:

此时我们vim进入code.i :会发现其有800多行

解释:预处理进行了多个工作,主要包括头文件展开、去注释、宏替换、条件编译等,而其中的头文件展开就是导致突然有800多行的原因;至于去注释、宏替换,可以自己在.c中写一个宏替换和注释,会发现预处理之后,注释被去掉了、宏被替换了!

至于条件编译的话,博主在上文提到的博客中没有说到,现在进行补充:

Q:条件编译是什么?

A:举个例子

现在我们创建了一个新的file.c,其内容如下:

此时直接gcc是会报错的,因为x是未定义的变量,但是却被使用,但是我们执行以下指令的时候:

gcc file.c -D x=1

解释:gcc 编译file.c文件并同时定义宏 x=1 ,所以我们现在就会生成一个a.out文件,我们对其执行一下,会发现其成功运行了:

这就是一种简单的条件编译,目前我们需了解条件编译的例子有两个:

①:在我们使用软件的时候,一些软件有专业版和社区版 ,本质就是条件编译起到的作用,让社区版的功能和专业版有所区别;

②:我们的头文件在写出来的时候 其实前后都是有条件编译的,一个头文件只有在第一次写的时候,才会被定义,后面在一个源文件中的重复包含头文件,均会被条件编译省略

2:gcc -S(编译)

用法:

gcc -S code.i -o code.s

解释:从现在开始对code.i文件进行翻译,当对其的编译工作做完的时候,就停下来。此时生成的文件我把他命名为code.s 

注意:可以对code.c进行操作,也可以对预处理之后的code.i进行操作,自由选择

如图:我们gcc -S后生成了code.s

此时我们vim进入code.s:

 

解释:编译这一步进行的工作是->首先检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,将代码翻译成汇编语言所以我们vim进入看见的都是会汇编语言!


 

3:gcc -c(汇编)

用法:

gcc -c code.s -o code.o

解释: 从现在开始对code.s文件进行翻译,当对其的汇编工作做完的时候,就停下来。此时生成的文件我把他命名为code.o 

 

如图:

 

此时我们vim进入code.o:

解释:汇编阶段是把编译阶段生成的 .s 文件转成目标 .o 文件,此时的.o文件中内容都是汇编代码转化为的二进制目标代码了。

但是此时的.o文件虽然是一个目标文件,但是叫作可重定位目标二进制文件,其是不可执行的

 

验证其不可执行:

对.o文件进行./执行:

Q:虽然演示出了不可执行,但是这.o文件对于wtt1来说没有x权限,有x权限应该能执行了?

A:好的,对wtt1增加x权限:

 

还变绿了,感觉真的行哦~

 

解释:依旧不行!报错 :无法执行二进制文件,所以这就证明了汇编生成的目标文件不能执行,因为我们少了链接这一步!需要链接到库,才能够形成可执行文件!

4:链接

链接无选项,用法:

gcc code.o

这样默认生成的就是a.out的可执行文件,我们也可以用-o选项命名的选择:

gcc code.o -o code.out

 

如图:

 

 解释:

  • 链接的主要任务就是将生成的各个 .o 文件进行链接,生成可执行文件。
  • gcc/g++不带-E、-S、-c选项时,就默认生成预处理、编译、汇编、链接全过程后的文件。
  • 若不用-o选项指定生成文件的文件名,则默认生成的可执行文件名为a.out。

 

此时我们vim进入code.out:

解释: 链接后生成的也是二进制文件。因为计算机只认识二进制
 

Q:你这链接之后,我感受不到变化啊,有什么什么办法让我感受一下链接体现在哪?

A:要查看一个文件是否链接了,有ldd指令和file指令两种方法

①:ldd

ldd指令即可,ldd指令用于打印可执行文件或共享库所依赖的动态链接库(.so 文件)

对比一下code.out和code.o 对于ldd指令的区别:

解释:信息说明了我们的code.out文件的确是链接到了库!(图中的/lib64/libc.so.6就是当前云服务器当中的C标准库)。

②:file

解释:dynamically linked 意味着动态链接

那库有类别吗?难道还有静态链表吗?

三:动态库和静态库

1:库的类别及优缺点

函数库一般分为静态库和动态库两种:

①:静态库是指编译链接时,把库文件的代码全部加入到可执行文件当中,因此生成的文件比较大,但在运行时也就不再需要库文件了,静态库一般以.a为后缀。


②:动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件当中,而是在程序运行时由链接文件加载库,这样可以节省系统的开销,动态库一般以.so为后缀。

动态链接:
 优点:省空间(磁盘的空间,内存的空间),bin体积小,加载速度快。
 缺点:依赖动态库,程序可移植性较差。

静态链接:
 优点:不依赖第三方库,程序的可移植性较高。
 缺点:浪费空间。

2:动态链接

Q:那我们写的.c 和 .cpp文件进行连接的时候,是采取那哪一种?

A:file指令就能知道

 解释:dynamically linked 意味着动态链接

3:静态链接

我们还可以强行对code.o文件进行静态链接到库,指令:gcc -static

注:当然也可以直接对code.c进行强行的静态链接,自由选择即可

gcc code.o -o code.out_static -static

我们静态链接生成的可执行文件取名为 code.out_static,方便区别于code.out

此时我们就有两个可执行文件了:

解释:由静态链接的缺点可知,静态链接是把库文件的代码全部加入到可执行文件当中,所以这就是为什么我们的code.out_static的大小是861288,远远大于code.out的原因!

我们可以通过ldd来查看code.out_static是否真的被静态链接了:

解释: 信息告诉我们:这个程序是静态链接的,没有依赖任何动态库(.so 文件),因此无法列出动态库依赖关系;所以这正好说明了的确进行了静态链接

再通过file来看一下code.out_static:

解释:statically linked 意味着静态链接

总结:Linux中的编译器gcc和g++默认都是动态链接的!

四:一些细节

1:巧记选项后后缀

Q:你上面的-E -S -c 选项;和 -E生成的.i ,-S生成的.s,以及-c生成的.o 文件,怎么记忆?

A:Esc就是我们键盘上的返回键,对应的就是预处理,编译,汇编,只需记住c小写即可;而iso三个字母对应的就是预处理,编译,汇编生成的文件后缀,我不喜欢ios系统,所以它叫iso

2:指定输出文件的重要性

注意:

-E一定会生成一个.i文件,所以我们一般指定写生成的.i文件的前缀,.s 文件和 .o 文件也是类似的道理!但其实其中的-E预处理比较特殊:

  • 如果不指定输出文件,预处理后的代码会直接输出到 标准输出(屏幕),而 不会自动生成 .i 文件

而其余的编译,汇编都会直接生成文件,而不是输出到标准输出(屏幕)!

3:gcc对后缀的要求

我们平时使用gcc,一般是对文件直接编译成可执行文件,但需要注意的是,我们编译的文件一定要是.c文件!

gcc hello.txt  # 默认会失败,因为 GCC 根据后缀名调用处理工具

相关文章:

  • 深入理解C#中的委托与事件:从基础到高级应用
  • 图片压缩工具 | 发布到咸鱼并配置网盘自动发货
  • 如何利用categraf的exec插件实现对Linux主机系统用户及密码有效期进行监控及告警?
  • 【Redis技术进阶之路】「原理分析系列开篇」探索事件驱动枚型与数据特久化原理实现(文件事件驱动执行控制)
  • C# Costura.Fody 排除多个指定dll
  • Cobra CLI 工具使用指南:构建 Go 语言命令行应用的完整教程
  • Java面试实战:从Spring到大数据的全栈挑战
  • QT6搭建和使用MQTT
  • 【LangChain】
  • 【Redis】第3节|深入理解Redis线程模型
  • Python中的__init__和__new__方法解析
  • 纵览网丨病毒学领域的 AI 变局:机遇、隐忧与监管之路
  • AI如何让你的智能设备电池更“聪明”?——Python实现智能电池管理
  • jdk 国内下载镜像站
  • 互联网商业模式全景解读:B2B、B2C、C2C及更多
  • Android高级开发第一篇 - JNI(初级入门篇)
  • 第一个桌面应用程序的创建
  • st倍增(st表)
  • [Rust_1] 环境配置 | vs golang | 程序运行 | 包管理
  • 配网导线自取电式视频监测装置
  • 上海自适应网站开发/培训机构退费纠纷一般怎么解决
  • html5 服装网站/成都网络推广外包
  • 网页制作与网站建设服务器/申请自己的网站
  • 乌鲁木齐做公司网站/网页自助建站
  • 卢松松网站/互联网营销师是哪个部门发证
  • 小说网站怎么做流量/百度热搜榜排名今日