• [Linux入门]---Linux编译器gcc/g++使用


    1.背景知识

    通过前面的学习,我们知道我们的代码变成能运行的可执行程序,要经历以下四个过程:

    1.预处理(进行宏替换)
    2.编译(生成汇编)
    3.汇编(生成机器可识别的代码)
    4.链接(生成可执行文件或库文件)

    那在Linux操作系统上gcc编译器编译运行代码的过程又是怎么样的呢?接下来让我们一起学习吧!

    2.gcc如何完成编译运行工作

    $ 格式 gcc [选项] 要编译的文件 [选项] [目标文件]
    
    • 1

    创建mycode.c文件,写入如下代码:

    #include      
    #define M 100      
          
    int main()      
    {      
    #ifdef DEBUG      
        printf("hello debug\n");      
    #else      
        printf("hello release\n");      
    #endif      
       // pintf("这是被注释掉的内容\n");    
       // pintf("这是被注释掉的内容\n");    
       // pintf("这是被注释掉的内容\n");    
       // pintf("这是被注释掉的内容\n");    
       // pintf("这是被注释掉的内容\n");    
       // pintf("这是被注释掉的内容\n");    
                                                                                                                                                                         
        printf("hello gcc:%d\n",M);                                                                                                            
        printf("hello gcc:%d\n",M);                                                                                                            
        printf("hello gcc:%d\n",M);                                                                                                            
        printf("hello gcc:%d\n",M);                                                                                                            
        printf("hello gcc:%d\n",M);                                                                                                            
        printf("hello gcc:%d\n",M);                                                                                                            
        printf("hello gcc:%d\n",M);                                                                                                            
        printf("hello gcc:%d\n",M);                         
        printf("hello gcc:%d\n",M);    
        printf("hello gcc:%d\n",M);    
        printf("hello gcc:%d\n",M);    
        return 0;    
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    指令:

    $ gcc -o mycode.exe mycode.c
    //-o 可以指定生成可执行文件名称,如果不指定,默认生成a.out可执行文件
    
    • 1
    • 2

    代码编译运行的结果为:
    在这里插入图片描述

    预处理(进行宏替换)

    预处理指令:

    $ gcc -E 源文件 -o 指定预处理文件名
    
    • 1
    • 预处理阶段是源文件文件转成目标文件
    • 选项-E,该选项的作用是让 gcc 在预处理结束后停止编译过程。
    • 选项“-o”是指目标文件,如果不带选项“-o”会预处理的结果放在显示屏上,“.i”文件为已经过预处理的C原始程序。
    • 预处理阶段的主要工作有:a.去注释,b.头文件展开;c.宏替换(不做类型检查);d.条件编译;

    输入指令:

    $ gcc -E mycode.c -o mycode.i
    $ gcc -E mycode.c -o mycode.i -D DEBUG//使用-D选项在外部可定义宏
    
    • 1
    • 2

    在这里插入图片描述

    输入该指令告诉gcc从现在开始程序的翻译,做完预处理工作就停下来,不要继续往下执行了。

    输入指令vim mycode.i查看预处理后的文件
    头文件展开:
    在这里插入图片描述
    在这里插入图片描述

    编译(生成汇编)

    输入编译指令:

    $ gcc -S mycode.i -o mycode.s
    
    • 1
    • 编译阶段是把预处理阶段生成的“.i”文件转成".s"目标文件
    • 在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言。
    • 用户可以使用“-S”选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。

    代码运行的结果为:
    在这里插入图片描述
    在这里插入图片描述

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

    汇编指令:

    $ gcc -c mycode.s -o mycode.o
    
    • 1
    • 汇编阶段是把编译阶段生成的“.s”文件转成".o"目标文件
    • 可使用选项“-c”就可看到汇编代码已转化为“.o”的二进制目标代码了
      输入指令的结果为:
      在这里插入图片描述
      在这里插入图片描述

    mycode.o为可重定位二进制文件,简称目标文件,Windows上目标文件为.obj文件,虽然已经是二进制文件,但是还不可以独立执行,需要经过链接才能执行!

    链接(生成可执行文件)

    $ gcc mycode.o -o mycode.exe
    
    • 1
    • 在成功编译之后,就进入了链接阶段,将可重定位二进制文件和库进行链接形成.exe可执行文件
      在这里插入图片描述

    3.函数库

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

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

    动态库

    windows系统中,动态库以.dll为后缀的文件,Linux系统,动态库为以.so为后缀的文件。库的命名规则:“libnameso.XXX"name为库的真正名字,其他为前后缀。
    输入指令查找C的标准库:

    ls /lib64/libc*
    //查找含/lib64/libc的库文件
    ls /lib64/libc.so*
    //查找动态库文件
    
    • 1
    • 2
    • 3
    • 4

    输入指令后代码运行的结果:
    在这里插入图片描述

    静态库

    windows系统中,静态库以.lib为后缀的文件,Linux系统,静态库为以.a为后缀的文件。我们的机器上默认只会安装动态库,静态库需要我们手动输入指令安装。
    安装C语言静态库指令如下:

    //root用户
    # yum install -y glibc-static//安装c的静态库
    # yun install -y libstdc++-static//安装c++的静态库
    //普通用户
    $ sudo yum install -y glibc -static
    $ yun install -y libstdc++-static
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    安装完成的结果如下:
    在这里插入图片描述
    在这里插入图片描述

    查找C语言静态库指令:

    $ ls /lib64/libc.a*
    
    • 1

    输入指令后代码运行的结果:
    在这里插入图片描述

    动静态库的区别

    小故事: 网瘾少年需要上网,你有两种方法,一种是跑到网吧上网,而你怎么知道哪里有网吧呢?原来你的好基友曾经告诉你某某路口向东转500米有一家网吧,于是每到放假的时候,你就可以跑到网吧去上网,但天有不测风云,这家网吧的老板没有营业执照被查封了,自此你的上网之路就断了;只好使用另一种方法,你每天上省吃俭用,终于三个月后攒够了钱,去一家二手电脑销售店购买了一台电脑,从此你便过上了自由自在的网民生活,不久后你去的这家二手电脑销售店由于非法经营被查封了,但这已经影响不到你了。

    动态链接:.o文件(网瘾少年)和动态库(网吧)链接,很高效但如果动态库没了,各个程序文件将无法运行,限制性很大;静态链接:.o文件(网瘾少年)会拷贝(购买)静态库(电脑)到文件中,会占用很大内存、很多时间(费时费钱),但库文件(电脑销售店没了)不存在了,各个程序文件不受影响仍可以正常运行!
    生成可执行文件的指令:

    $ gcc mycode.c -o mycode.exe//进行动态链接
    $ gcc mycode.c -o mycode_static.exe -static//进行静态链接
    
    • 1
    • 2

    输入指令后代码运行的结果:
    在这里插入图片描述

    ldd 可执行文件//查找链接的动态库
    
    • 1

    在这里插入图片描述

    file 可执行文件名//显示符号链接的文件类型
    
    • 1

    在这里插入图片描述

    ①在Linux中,编译形成可执行程序,由编译器提供动态库,默认采用动态链接;如果想要以静态链接的方式,生成可执行文件,需要添加-static选项;②静态链接生成的可执行文件比动态链接生成的可执行文件大很多。

    动静态库区别总结:
    ①如果没有静态库,不可以使用-static选项进行静态链接;
    ②如果没有动态库,只有静态库,gcc编译器将会去寻找静态库进行链接;
    ③gcc默认优先动态链接,-static选项改变的是链接的优先级,使用后所有的链接都为静态链接;
    ④我们平时写的代码生成可执行文件时,不一定全部是动态链接或静态链接,而极有可能是动态链接和静态链接混合生成可执行文件;
    ⑤动态链接优点:动态库是共享库,可以有效地节省资源(磁盘空间、内存空间,网络空间等);缺点:动态库一旦缺失,使用动态链接的可执行程序将无法运行!
    ⑥静态链接的优点:不依赖库,程序可以独立运行;缺点:生成的可执行文件体积大,比较消耗资源(磁盘空间、内存空间,网络空间等)。

    4.gcc选项

    -E 进行预处理工作,不生成文件,你需要把它重定向输出到一个.i文件里面
    -S 编译到汇编语言到.s文件中,不进行汇编和链接
    -c 进行汇编工作,编译到.o可重定位二进制目标文件(目标文件)
    -o 将目标文件和库文件进行链接输出到指定的可执行文件
    -static 此选项对生成的文件采用静态链接 -g 生成调试信息。GNU 调试器可利用该信息。
    -shared 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库
    -O0
    -O1
    -O2
    -O3 编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高
    -w 不生成任何警告信息。
    -Wall 生成所有警告信息。

  • 相关阅读:
    PCL 二次曲面拟合法计算点云高斯、平均曲率与法向量(C++详细过程版)
    linux自定义开机自启多个服务的脚本
    Linux服务器部署JavaWeb后端项目
    Jmeter常用参数化技巧总结!
    【入门-08】系统控制单元(SCU)
    华为云大数据BI 为中小型企业智慧运营保驾护航
    UseGalaxy.cn生信云|生物信息必备技能-出版级别的circos圈图绘制
    Nacos注册中心与配置管理
    【SQL刷题】DAY14----SQL使用子查询专项练习
    2022/8/15 考试总结
  • 原文地址:https://blog.csdn.net/m0_74288306/article/details/132522494