• 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 }
    ~
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

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

    在这里插入图片描述


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

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

    在这里插入图片描述


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

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

    在这里插入图片描述


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

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

    在这里插入图片描述


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

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

    在这里插入图片描述


    预处理

    我们来看看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 重定向,内容默认是打印显示在活动桌面上
    
    • 1
    • 2

    在这里插入图片描述


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

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

    在这里插入图片描述


    打开预处理后的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
    不过它会重新进行一个预处理后,——> 在进行编译,生成汇编代码。因为这里我们已经有了经过预处理过后的文件的,所有我们可以直接对它进行编译,生成汇编代码
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述


    汇编代码(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
    不过,不过它会重新进行一个预处理后,——> 在进行编译,生成汇编代码,——> 再对汇编代码,进行一个汇编操作,生成二进制目标文件
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述


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

    在这里插入图片描述


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

    在这里插入图片描述


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

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

    在这里插入图片描述


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

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

    在这里插入图片描述


    链接

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

    链接: 本质上就是引入我们在代码中使用的第三方库(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
    不过需要经过一下 :预处理——> 编译——> 汇编——> 链接 可执行程序
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述


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

    [linux@localhost dir2]$ ./mybin
    
    • 1

    在这里插入图片描述


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

    在这里插入图片描述


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

    [linux@localhost dir2]$ ldd mybin
    
    • 1

    在这里插入图片描述


    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
    
    • 1

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

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

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

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

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

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


    记忆方式

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

    在这里插入图片描述

    最后:

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

  • 相关阅读:
    安全设备和防火墙
    【第二章 数据的表示和运算】d1
    【Java后台】从零开始的Java后台开发(二)
    jdk8 map方法list<Object1> 处理一下转成另一个List<Obj>
    PYTHON+CH341 3线SPI驱动UC1601 LCD实现汉字显示
    脏牛提权 liunx
    《Linux从练气到飞升》No.22 Linux 进程间通信
    python threading和multiprocessing模块基本用法实例分析
    华为鸿蒙手表开发之动态生成二维码
    微信小程序地图功能详解
  • 原文地址:https://blog.csdn.net/weixin_61635597/article/details/125898779