简谈GCC那些事

GCC的学习笔记

简谈GCC那些事

1.什么是GCC

  • GCC: GNU Compiler Collection,即 GNU 编译器套件。可以处理C、 C++、Go、Objective-C 等多种编译语言编写的程序。

2.环境配置

  • 安装gcc,一般Linux下均已经安装好gcc。如果windows想安装gcc,则需要先安装MinGW,然后依托该软件安装gcc.
  • 判断环境是否安装好了?——cmd中输入gcc -v或者g++ -v。

3. gcc和g++的认识和区别

  • 只要是 GCC 支持编译的程序代码,都可以使用 gcc 命令完成编译。
  • gcc 是 GCC 编译器的通用编译指令,因为根据程序文件的后缀名,gcc 指令可以自行判断出当前程序所用编程语言的类别。
  • 使用 g++ 指令,则无论目标文件的后缀名是什么,该指令都一律按照编译 C++ 代码的方式编译该文件。
  • 对于编译执行 C++ 程序,使用 gcc 和 g++ 也是有区别的。很多 C++ 程序都会调用某些标准库中现有的函数或者类对象,而单纯的 gcc 命令是无法自动链接这些标准库文件的。
  • 使用 gcc 指令来编译执行 C++ 程序,需要手动为其添加 -lstdc++ -shared-libgcc 选项,表示 gcc 在编译 C++ 程序时可以链接必要的 C++ 标准库。
gcc -xc++ -lstdc++ -shared-libgcc //等价于g++
//-x后面指明是何种语言

4.gcc编译标准

  • 根据gcc的版本,支持不同的编译标准,如C99,C11,C++98,C++11等。
  • 手动配置编译标准,可以借助-std选项,如下:
gcc/g++ -std=C11  //C11可以换成其他编译标准

5.C/C++源代码生成可执行程序的4个过程

  • 分别是预处理、编译、汇编和链接。
    生成可执行文件的过程
5.1 预处理(Preprocessing)
  • 预处理过程主要是处理那些源文件和头文件中以#开头的命令,比如 #include、#define、#ifdef 等。
  • 处理的规则一般如下:
    • (1)将所有的#define删除,并展开所有的宏定义。
    • (2)处理所有条件编译命令,比如 #if、#ifdef、#elif、#else、#endif 等。
    • (3)处理#include命令,将被包含文件的内容插入到该命令所在的位置,这与复制粘贴的效果一样。注意,这个过程是递归进行的,也就是说被包含的文件可能还会包含其他的文件。
    • (4)删除所有的注释//和/* … */。
    • (5)添加行号和文件名标识,便于在调试和出错时给出具体的代码位置。
    • (6)保留所有的#pragma命令,因为编译器需要使用它们。
  • 预处理产物:生成.i文件。.i文件也是包含C语言代码的源文件,只不过所有的宏已经被展开,所有包含的文件已经被插入到当前文件中
  • 在gcc中生成i文件命令
gcc -E D:/project/demo.c -o D:/project/demo.i
//命令中的E表示只进行预编译  -o表示指定生成文件名
5.2 编译(Compilation)
  • 编译就是把预处理完的文件进行一些列的词法分析、语法分析、语义分析以及优化后生成相应的汇编代码文件。
  • 编译产物:生成.s文件。
    在gcc中生成s文件命令
//方法1:将C文件直接编译成s文件。
gcc -S D:/project/demo.c -o D:/project/demo.s
//方法2:将预编译i文件再编译成s文件。
gcc -S D:/project/demo.i -o D:/project/demo.s
//-S表示不进行汇编
  • .s的汇编文件阅读比较困难,可以将.c文件编译成汇编源文件。命令为:
gcc -S demo.c -fovrbose-asm //编译出的demo.s文件中会自行注释对应的C代码。
5.3 汇编(Assembly)
  • 汇编的过程就是将汇编代码转换成可以执行的机器指令。
  • 大部分汇编语句对应一条机器指令,有的汇编语句对应多条机器指令。
    • 汇编产物:生成.o文件,叫做目标文件,已经是二进制文件了。
      在gcc中生成o文件命令
//方法1:将C文件直接编译成o文件。
gcc D:/project/demo.c -o D:/project/demo.o
//方法2:将预编译i文件再编译成o文件。
gcc D:/project/demo.i -o D:/project/demo.o
//方法3:将汇编s文件编译成o文件。
gcc -c D:/project/demo.s -o D:/project/demo.o // -c是小写的且不能省略。
5.4 链接(Linking)
  • 链接作用:将所有的二进制目标文件组织成一个可以执行的二进制文件。让目标文件中的某些全局变量或者函数能够找到地址,才能执行。
      • 链接产物:生成.out文件或者.exe文件。
//方法1:将C文件直接编译成o文件。
gcc D:/project/demo.c -o D:/project/demo.exe
//方法2:将预编译i文件再编译成s文件。
gcc D:/project/demo.i -o D:/project/demo.exe

6 gcc一步到位成程序的命令

gcc D:/demo.c  //在linux下生成demo.out
D:/demo.out //执行demo
g++ D:/demo.c //如果编译C++则将gcc改成g++
//如果想控制生成程序的格式
gcc D:/demo.c -o D:/demo.exe
gcc D:/demo.c -o D:/demo.out

7 gcc编译多个文件

//方法1
gcc -c D:/demo.c D:/demo2.c //不能使用-o指定输出文件名了
//方法2
1.切换到当前路径下,然后输入如下命令
gcc *.c -o mainname.exe  //mainname是自己取的程序名

8 gcc使用链接库

-编译命令如下:

//方法一
gcc demo.c -o demo.out -lm
//-lm表示:l为lib的缩写,m为math.h的基本名称,如果是其他库则换成其他名称即可。
//方法二
gcc demo.c -o demo.out /usr/lib/libm.a
//libm.a表示链接库名
// /usr/lib表示链接库路径
  • 库文件:该文件内部通常包含不少于一个目标文件。可以理解为将多个目标文件压缩成一个压缩文件。
  • 库文件的优点:可以让程序员调用已经开发的功能化模块,比如L:printf函数。
  • 库文件的使用:库文件是无法直接使用的,只能通过头文件间接调用。所以库文件都需要提供相应的头文件作为调用它的接口。
  • 库文件和头文件的区别:头文件只存储变量、函数或者类等这些功能模块的声明部分,库文件才负责存储各模块具体的实现部分。这样的好处,在于实现了库文件内部内容的封装,使用时不需要知道其内部的具体实现。
  • 采用静态链接方式实现链接操作的库文件,称为静态链接库;采用动态链接方式实现链接操作的库文件,称为动态链接库
8.1 静态链接库
  • 静态链接库实现链接操作的方式是:程序文件中哪里用到了库文件中的功能模块,GCC 编译器就会将该模块代码直接复制到程序文件的适当位置,最终生成可执行文件。
  • 优点:可移植性强。生成的可执行文件不再需要任何静态库文件的支持就可以独立运行。
  • 劣势:容易造成代码冗余。如果程序文件中多次调用库中的同一功能模块,则该模块代码势必就会被复制多次,生成的可执行文件中会包含多段完全相同的代码。
  • 和使用动态链接库生成的可执行文件相比,静态链接库生成的可执行文件的体积更大。
  • 在 Linux 系统中,静态链接库文件的后缀名通常用 .a 表示;在 Windows 系统中,静态链接库文件的后缀名为 .lib。
8.2 动态链接库
  • 动态链接库,又称为共享链接库。和静态链接库不同,采用动态链接库实现链接操作时,程序文件中哪里需要库文件的功能模块,GCC 编译器不会直接将该功能模块的代码拷贝到文件中,而是将功能模块的位置信息记录到文件中,直接生成可执行文件。
  • 生成的可执行文件是无法独立运行的。采用动态链接库生成的可执行文件运行时,GCC 编译器会将对应的动态链接库一同加载在内存中,才能保证程序使用。
  • 优势和劣势恰好和静态链接库相反:
    • 由于可执行文件中记录的是功能模块的地址,真正的实现代码会在程序运行时被载入内存,这意味着,即便功能模块被调用多次,使用的都是同一份实现代码(这也是将动态链接库称为共享链接库的原因)。
    • 可移植性差。生成的可执行文件无法独立运行,必须借助相应的库文件。
  • 在 Linux 系统中,动态链接库的后缀名通常用 .so 表示;在 Windows 系统中,动态链接库的后缀名为 .dll。
  • GCC 编译器生成可执行文件时,默认情况下会优先使用动态链接库实现链接操作,除非当前系统环境中没有程序文件所需要的动态链接库,GCC 编译器才会选择相应的静态链接库。

9 gcc制作链接库

9.1 制作静态链接库
  • 并非任何一个源文件都可以被加工成静态链接库,其至少需要满足以下 2 个条件:
    • (1)源文件中只提供可以重复使用的代码,例如函数、设计好的类等,不能包含 main 主函数
    • (2)源文件在实现具备模块功能的同时,还要提供访问它的接口,也就是包含各个功能模块声明部分的头文件
  • 制作步骤
    • 将所有指定的源文件,都编译成相应的目标文件。
gcc -c sub.c add.c  //将这两个函数直接编译成目标文件。
    • 使用 ar 压缩指令,将生成的目标文件打包成静态链接库,格式如下:
ar rcs 静态链接库名称 目标文件1  目标文件2
//方法1:
ar rcs libmath2.a add.o sub.o //静态连接库的名字不能随意取,格式为libXXX.a(linux),libXXX.lib(windows),XXX为静态库名称;
//方法2:
ar rcs libmymath.a *.o  //其中*.o表示将本目录下的目标文件都压缩成lib库。
9.2 使用静态链接库
  • 使用方法:在程序的链接阶段,将静态链接库和其他目标文件一起执行链接操作,从而生成可执行文件。
方法1:
gcc -static demo.o libmymath.a  //会自动生成一个名为a.out产物
gcc -static demo.o libmymath.a -o main.out //用-o给产物命名为main.out。
方法2:gcc demo.o -static -L /root/work/ -lmymath
//-static 选项表示强制gcc编译器使用静态链接库
//-L 后面跟lib库所在存储路径
//-lmymath  -l用于指明lib库名称,mymath是lib库名称。

10 gcc制作动态连接库

  • **注意:**动态链接库的命令规则和静态链接库完全相同,只不过在 Linux 发行版系统中,其后缀名用 .so 表示;Windows 系统中,后缀名为 .dll。
10.1 制作
  • 动态链接库的创建方式有 2 种:
  • (1)直接使用源文件创建动态链接库
gcc -fpic -shared 源文件名 -o 动态链接名
//-shared 选项用于生成动态链接库
//-fpic(还可写成 -fPIC)选项的功能是:令 GCC 编译器生成动态链接库(多个目标文件的压缩包)时,表示各目标文件中函数、类等功能模块的地址使用相对地址,而非绝对地址。
gcc -fpic -shared sub.c add.c -o libmylib.so
  • (2)先使用 gcc -c 指令将源文件编译为目标文件时,也需要使用 -fpic 选项。目的是为了生成动态链接库并能正常使用。然后用gcc -shared 目标文件 -o libXXX.so(XXX为lib名称)。
gcc -c -fpic add.c sub.c
gcc -shared add.o sub.o -o libmymath3.os
10.2 使用
  • 可借助动态链接库成功生成可执行文件:
gcc demo.c libmymath3.os -o main.exe  //生产main.exe
gcc demo.c libmymath3.os -o main.out  //生产main.out
  • 此时编译的main.exe或者main.out并不能正常直接用./main.out执行,会报错找不到动态链接库libmymath3.os。
  • 解决上述简单方法是:将链接库文件移动到标准库目录下(例如 /usr/lib、/usr/lib64、/lib、/lib64)。还有其他方法不在这深入学习。
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值