Linux编译器-gcc的使用

Linux编译器-gcc的使用

在这里插入图片描述


每博一文案

听过这样一句话,世间所有的内向都是因为聊错了对象。

人与人之间相处,最怕的就是你不相信你看到的,我却相信别人口中的我,

其实你不需要从别人口中来了解我。因为我对每个人都不太一样。

若你能走近一点,亲眼凝视我的眼睛,亲耳听听我的声音,放下芥蒂与我相处,

以你心的,换我心,你会发现,我跟别人口中所说的真的比太一样。

都说时间识人,落难之心,道听途说来的,只是别人的故事,

自己用心去了解到的,才是最真的我们

​ —————— 一禅心灵庙语



我们知道一个C语言程序变成一个可执行程序是要经过如下过程的:

预处理 ——> 编译 ——> 汇编 ——> 链接 这四个基本过程才可以生成一个可执行的 .exe文件

在这里插入图片描述


gcc的直接编译

我们编写一个C语言程序:如下

1 #include<stdio.h>
  2 
  3 #define N 123
  4 
  5 int main()
  6 {
  7 
  8   printf("hello,%d\n",N);
  9   printf("hello,%d\n",N);
 10   printf("hello,%d\n",N);
 11   printf("hello,%d\n",N);
 12   // printf("hello,%d\n",N);
 13   // printf("hello,%d\n",N);
 14   // printf("hello,%d\n",N);
 15   // printf("hello,%d\n",N);
 16                                                                                                                            
 17   return 0;
 18 }
~

我使用的是 vim 编译的,对于 vim 大家想要了解的,可以移步到 🔜🔜🔜 你一定可以看懂的:Linux编辑器-vim的使用_ChinaRainbowSea的博客-CSDN博客 如下:

在这里插入图片描述


编写好C语言程序后,我们可以使用 gcc 编译C语言程序,变成可执行程序

[linux@localhost dir2]$ gcc test.c
对名为 “test.c"的C语言文件,使用 gcc 进行编译,没有重向的话,默认生成的可执行程序,是 a.out

在这里插入图片描述


生成了 a.out 可执行程序,我们可以使用 ./ + 可执行文件名 ,运行看看,如下:

[linux@localhost dir2]$ ./a.out
运行一下名为 a.out 的程序

在这里插入图片描述


我们可以加上 -o(重定向) ,把可执行程序,重定向到我们指定的文件名中,没有该文件名的文件会自动创建如下:

[linux@localhost dir2]$ gcc test.c -o mybin
将 gcc test.c 编译生成的可执行程序,重定向(复制,拷贝)到 mybin 中

在这里插入图片描述


该重定向的文件也是可以使用 ./+文件名 运行的,结果是一样的 如下:

[linux@localhost dir2]$ ./mybin
运行一下,名为mybin的程序

在这里插入图片描述


预处理

我们来看看C语言程序,预处理后的内容

预处理阶段主要进行了头文件的展开、去注释、宏替换、条件编译

头文件的展开: 使用的头文件的所在路径,的绝对路径的展开,使用到头文件 中的有关函数,变量拷贝到该原始程序中,所以经过 预处理后 的文件大小会变得有些

去注释: 注释的代码不使用,去了

宏替换: 将使用宏了的变量,变为数值

我们可以使用 gcc -E xxx(需要预处理的C语言文件) -o xxx.i (重定向为后缀为.i 的C原始程序),表示:对 C文件只进行 预处理 操作后就停下来,后面的编译,汇编等等都不执行

选项 ”-E" ,大写的 e 该选项的作用是让 gcc预处理 结束后就停止,不再进行后面的操作

选项 “-o: ,是指将内容重定向到目标文件中去,”.i" 文件为已经,经过预处理 过的 C原始程序

我们这里以 刚刚的 test.c C语言文件为例

[linux@localhost dir2]$ gcc -E test.c
未使用 -o 重定向,内容默认是打印显示在活动桌面上

在这里插入图片描述


我们带上重定向 -o 到文件名为 mybin.i 文件中,操作如下:

[linux@localhost dir2]$ gcc -E test.c -o mybin.i
将内容重定向到 文件名为 mybin.i 中,没有自动创建出来

在这里插入图片描述


打开预处理后的mybin.i 文件,和没有预处理过的 test.c文件存在什么样的不同点

我们这里都使用 vim 打开,如下:

mybin.i 存在对应有关头文件的路径的展开,以及头文件中使用到的变量,方法的拷贝,行数上的增加 854,宏的替换,注释的去除

注意: 预处理过的内容 mybin.i 文件,还是C语言 没有改变,因为其中还有我们熟悉的 main,printf 的函数

在这里插入图片描述

在这里插入图片描述


在这里插入图片描述


编译(生成汇编代码)

在这个阶段中,gcc首先要检查代码中的规范性,是否存在语法上的错误等等,以确定代码实际需要做的工作,在检查无误后,gcc 把代码翻译成 汇编语言 ,可以使用 “-S” 大写的 S 选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。

我们可以使用 gcc -S xxx(需要编译的文件) -o xxx.i (重定向为后缀为.s的C原始程序) 表示:对文件进行编译(生成汇编代码),就停止了,而不进行后续的 汇编、链接操作,

这里同样以我们的 test .c 文件为例

[linux@localhost dir2]$ gcc -S mybin.i -o mybin.s
对 mybin.i(预处理后)的文件,进行编译,生成汇编代码
当然,这里也是可以是 test.c 未经过预处理的源文件,如下:
[linux@localhost dir2]$ gcc -S test.c -o mybin.s
不过它会重新进行一个预处理后,——> 在进行编译,生成汇编代码。因为这里我们已经有了经过预处理过后的文件的,所有我们可以直接对它进行编译,生成汇编代码

在这里插入图片描述


汇编代码(mybin.i) 与 test.c(原文件)的比较

在这里插入图片描述


汇编(生成机器可识别代码)

汇编 过程把 经过编译处理生成的汇m j编代码,生成二进制目标代码
汇编阶段是把编译阶段生成的 “.s” 文件转成 二进制目标文件**“.o”** ,可以使用 选项 ”-c"(小写的 c) 就可以看到汇编代码已转为 “.o" 的二进制目标代码了

我们可以使用 gcc -c xxx(需要编译的文件) -o xxx.i (重定向为后缀为.o的C原始程序) 表示:对文件进行汇编**(生成二进制目标代码)** ,就停止了,而不进行后续的链接操作

同样以 test 文件为例

[linux@localhost dir2]$ gcc -c mybin.s -o mybin.o
对 mybin.s 汇编代码,进行汇编生成二进制目标文件 mybin.o
同样我们也是可以直接对 test.c源文件,进行汇编操作的,如下:
[linux@localhost dir2]$ gcc -c test.c -o mybin.o
不过,不过它会重新进行一个预处理后,——> 在进行编译,生成汇编代码,——> 再对汇编代码,进行一个汇编操作,生成二进制目标文件

在这里插入图片描述


test.c (源文件) 与 mybin.s (二进制目标文件)

在这里插入图片描述


注意该生成的二进制目标文件是无法,运行的(不可执行),因为这仅仅是把我们所写的代码汇编生成了二进制的目标文件,并没有把我们导入头文件中的库函数中,方法 ,变量汇编成二进制目标文件,所以是无法运行的,我们可以试试看

在这里插入图片描述


没有权限我们把,可执行权限加上,对于文件的权限的管理,大家可以移步到 🔜🔜🔜 Linux 的权限命令_ChinaRainbowSea的博客-CSDN博客

linux@localhost dir2]$ chmod u+x mybin.o

在这里插入图片描述


再运行看看,结果还是不行,

[linux@localhost dir2]$ ./mybin.o

在这里插入图片描述


链接

经过了 预处理 ——> 编译 (生成汇编代码)——> 汇编(生成二进制代码)——> 链接

链接: 本质上就是引入我们在代码中使用的第三方库(c库),拷贝到我们的代码中,默认链接的是 C库 (由编译器和文件共同决定),所以不需要带 选项,直接使用 gcc 加上 重定向 -o ,操作如下:

[linux@localhost dir2]$ gcc mybin.o -o mybin
将 mybin.o 二进制目标文件 链接成 mybin 可执行程序
我们也可以使用和开头中的 gcc的直接编译一样,对源文件(test.c),进行编译链接
[linux@localhost dir2]$ gcc test.c -o mybin
不过需要经过一下 :预处理——> 编译——> 汇编——> 链接 可执行程序

在这里插入图片描述


运行看看, 链接后的二进制文件,可以运行

[linux@localhost dir2]$ ./mybin

在这里插入图片描述


test.c(源文件) 与 mybin(链接后的可执行文件)

在这里插入图片描述


我们可以使用ldd 命令,查看 对应链接的库的所在路径

[linux@localhost dir2]$ ldd mybin

在这里插入图片描述


libc.so.6 :动态库,库真正的名字是: 去掉前缀 lib, 去掉 .xxxx 点后面的,剩下的就是库的名字,这里是 c 库

lib.a : 静态库,库真正的名字是: 去掉前缀 lib, 去掉 .xxxx 点后面的,剩下的就是库的名字,这里是 c 库


函数库

我们的 C程序 中共,并没有定义 ”printf" 的函数实现,且在 预编译 中包含的 stdio.h 中也只有该函数的声明,而没有定义该函数的实现,那么是在哪里实现 printf 函数的呢?

答案: 是系统把这些函数实现都被 ,做到名为 libc.so,6 的库文件中去了,在没有特别指定时候,gcc 会系统默认的搜索路径,“/usr/lib" 下进行查找与系统变量类似 ,也就是链接lib.c.so.6 库函数中去,这样就能实现函数 ”printf" 了,而这也就是链接的作用

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

静态库 是指 编译链接时 ,把库文件的代码全部加入到 可执行文件中 因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为 “.a" ,使用 -static 命令,导入静态库

再使用 -static 命令之前我们需要先安装一下,具体原因:大家可以移步至:/usr/bin/ld: cannot find -lc错误原因及解决方法

linux@localhost]$ sudo yum install glibc-static

安装好后,我们导入静态库 -static

[linux@localhost dir2]$ gcc test.c -o mybin_s -static

如下图我们可以看到,其最明显的结果是:导入静态的库,生成的可执行程序,在存储大小上明显比较大许多
在这里插入图片描述

动态库与之相反,在编译链接时并没有把库文件的代码到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为 ”.so" ,如前面所述的 lib.so.6 就是动态库。gcc 在编译时默认使用动态库,所以不用带选项,完成了链接之后,gcc 就可以生成可执行文件,如下所示:

[linux@localhost dir2]$ gcc test.c -o mybin

gcc 默认生成的二进制程序,是动态链接的,这点可以通过 file 命令验证


记忆方式

对于上述gcc 命令的记忆技巧,如下图所示:

在这里插入图片描述

最后:

限于自身水平,其中存在的错误,希望大家给予指教,韩信点兵多多益善,谢谢大家,后会有期,江湖再见!

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值