Linux基础开发工具(gcc/g++篇)

目录

1.Linux编译器-gcc/g++使用

1.背景知识

2.gcc编译选项

3.分段

1.预处理(进行宏替换)

2.编译(生成汇编)

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

4.链接(生成可执行文件或库文件)

4.动态链接和静态链接

5.gcc其他常用选项 - 了解即可


1.Linux编译器-gcc/g++使用

gcc只能用来编译C语言,g++又能编译C又能编译C++

两者使用是相同的,所以统一用gcc来说明。

1.背景知识

1. 预处理(进行宏替换/去注释/条件编译/头文件展开等)

2. 编译(生成汇编)

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

4. 链接(生成可执行文件或库文件) 

2.gcc编译选项

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

我们先来简单体验一下  编译 C 代码并生成可执行文件

我们现在有一个code.c的文件

gcc code.c        这样就生成了一个可执行程序

./a.out                运行

或者gcc code.c -o mycode(mycode可以随便取名)


或者 gcc -o mycode.exe code.c

3.分段

[user1@iZ5waahoxw3q2bZ 26-4-14]$ ll
total 4
-rw-rw-r-- 1 user1 user1 74 Apr 14 18:23 code.c

1.预处理(进行宏替换)

-E:开始进行程序编译,在预处理完的时候,就停下来

• 预处理功能主要包括宏定义,文件包含,条件编译,去注释等。

• 预处理指令是以#号开头的代码行。

• 实例: gcc –E hello.c –o hello.i

• 选项“-E”,该选项的作用是让 gcc 在预处理结束后停止编译过程。

• 选项“-o”是指目标文件,“.i”文件为已经过预处理的C原始程序。

[user1@iZ5waahoxw3q2bZ 26-4-14]$ gcc -E code.c -o code.i        //用code.c生成code.i
[user1@iZ5waahoxw3q2bZ 26-4-14]$ ll
total 24
-rw-rw-r-- 1 user1 user1    74 Apr 14 18:23 code.c
-rw-rw-r-- 1 user1 user1 16873 Apr 14 18:33 code.i

可以看到我们的code.c源文件代码就7行,但是预处理之后,整个源文件有了几百行

为什么会有这么多行呢?

根本来说是因为头文件展开

进行宏替换/去注释/条件编译/头文件展开等

如何理解条件编译?

聊一聊编译器?发展

2.编译(生成汇编)

-S:开始编译,编译完了,就停下来

• 在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作, 在检查无误后,gcc 把代码翻译成汇编语言。

• 用户可以使用“-S”选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。

• 实例: gcc –S hello.i –o hello.s

[user1@iZ5waahoxw3q2bZ 26-4-14]$ gcc -S code.i -o code.s
[user1@iZ5waahoxw3q2bZ 26-4-14]$ ll
total 28
-rw-rw-r-- 1 user1 user1    74 Apr 14 18:23 code.c
-rw-rw-r-- 1 user1 user1 16873 Apr 14 18:33 code.i
-rw-rw-r-- 1 user1 user1   448 Apr 14 18:34 code.s

形成汇编语言
为什么C/C++编译,要先完成汇编?

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

-c:开始编译,汇编完成,就停下来

• 汇编阶段是把编译阶段生成的“.s”文件转成目标文件

• 读者在此可使用选项“-c”就可看到汇编代码已转化为“.o”的二进制目标代码了

• 实例: gcc –c hello.s –o hello.o

[user1@iZ5waahoxw3q2bZ 26-4-14]$ gcc -c code.s -o code.o
[user1@iZ5waahoxw3q2bZ 26-4-14]$ ll
total 32
-rw-rw-r-- 1 user1 user1    74 Apr 14 18:23 code.c
-rw-rw-r-- 1 user1 user1 16873 Apr 14 18:33 code.i
-rw-rw-r-- 1 user1 user1  1496 Apr 14 18:35 code.o
-rw-rw-r-- 1 user1 user1   448 Apr 14 18:34 code.s

乱码

code.o---可重定位目标文件,win,vs2022, xxx.obj
    已经是二进制的文件了
    我们的源文件中,会包含很多的库方法,需要经过链接才能可执行

4.链接(生成可执行文件或库文件)

-o:开始链接,链接完成,就停下来

• 在成功编译之后,就进入了链接阶段。 • 实例: gcc hello.o –o hello

[user1@iZ5waahoxw3q2bZ 26-4-14]$ gcc code.o -o code
[user1@iZ5waahoxw3q2bZ 26-4-14]$ ll
total 44
-rwxrwxr-x 1 user1 user1  8440 Apr 14 18:35 code
-rw-rw-r-- 1 user1 user1    74 Apr 14 18:23 code.c
-rw-rw-r-- 1 user1 user1 16873 Apr 14 18:33 code.i
-rw-rw-r-- 1 user1 user1  1496 Apr 14 18:35 code.o
-rw-rw-r-- 1 user1 user1   448 Apr 14 18:34 code.s

巧记

程序的翻译过程ESc

文件iso

如果只带-c,不带任何其他的。那么默认是生成同名的结构。

[user1@iZ5waahoxw3q2bZ 26-4-14]$ touch code1.c code2.c
[user1@iZ5waahoxw3q2bZ 26-4-14]$ ll
total 4
-rw-rw-r-- 1 user1 user1  0 Apr 14 18:52 code1.c
-rw-rw-r-- 1 user1 user1  0 Apr 14 18:52 code2.c
-rw-rw-r-- 1 user1 user1 74 Apr 14 18:23 code.c
[user1@iZ5waahoxw3q2bZ 26-4-14]$ gcc -c code.c
[user1@iZ5waahoxw3q2bZ 26-4-14]$ ll
total 8
-rw-rw-r-- 1 user1 user1    0 Apr 14 18:52 code1.c
-rw-rw-r-- 1 user1 user1    0 Apr 14 18:52 code2.c
-rw-rw-r-- 1 user1 user1   74 Apr 14 18:23 code.c
-rw-rw-r-- 1 user1 user1 1496 Apr 14 18:52 code.o

 

一般喜欢先变成.o,然后再通过gcc进行链接

为什么呢?

1.编译器在编译时不仅仅要形成可执行程序,有可能还要形成库。形成库其实就是把所有.o文件打个包。如果要形成库就不用形成可执行程序,就必须形成.o,最后形成对应操作。

2.目前使用vs编译时形成一个可执行程序,自动化代码可能形成很多程序,所以要把.o自由组合,一次性形成多个可执行程序。

4.动态链接和静态链接

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

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

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

ldd code 命令用于查看可执行文件的动态库依赖关系

c标准库,libc.so

库:
分两类:
1.动态库:   Linux(.so)    windows(.dll)
2.静态库:   Linux(.a)     windows(.lib)

Linux中命令依赖c标准库

重新改code.c

把#define M注释

-D 是 GCC(以及其他许多编译器)的一个编译选项,用于在命令行中定义宏,效果等同于在源代码中使用 #define

如何理解条件编译?

    gcc code.c -o code -DM
    gcc支持命令行级别的宏定义 -D
    gcc code.c -o code -DM=100
                        #define M 100->插入到我们的代码中
    预处理的本质就是修改编辑我们的文本代码

条件编译的用途?
    1.对软件进行专业度,收费情况进行区分(业务)。使用条件编译,可以进行代码动态裁剪
    2.内核源代码也是采用条件编译进行代码裁剪
    3.开发工具,应用软件

为什么C/C++编译,要先完成汇编?
    开关

    打孔编程        二进制

    汇编语言

        

          助记符      

    C语言                       编译器

    C++/java/go/python...

    C语言用编译器变成汇编然后变成二进制

编译器的语言自举过程:

编译器就产生了---那么编译器在最开始用什么写呢?---第一版二进制版汇编编译器---编译汇编语言了---之后版再用汇编语言,写一个汇编编译器

在这里涉及到一个重要的概念: 库

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

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

所谓库就是一套方法或者数据集,为我们开发提供最基本的保证(基本接口,功能,加速我们二次开发)

什么叫做动静态库,什么叫做动静态链接,如何理解?

    库:
    1.动态库:   Linux(.so)    windows(.dll)
    2.静态库:   Linux(.a)     windows(.lib)

    c语言:
    libc.so     libc.a   

Linux中关于库的命名去掉lib前缀,去掉点后面的后缀,就是这个库的真实的名字

    动态库内部实现的方法                               让我们自己写的程序能在库中找到方法   
    我们自己的程序,会使用库中的方法            链接起来------形成可执行程序
                                                      执行目标方法,需要跳转到库中执行,完了再返回


    动态链接,让我们的程序,能找到库中的方法的地址!      共享库--被多个程序共享,一旦缺失,会导致所有程序,无法执行!
    静态链接,把我们程序中使用的库方法,拷贝给自己!     静态库只有在链接的时候有用,一旦执行可执行程序,静态库可以不再需要

动态链接是什么时候链的?

动态链接的“链接”动作发生在程序加载时运行时,而不是编译/链接阶段

  • 程序加载时链接(最常见):当操作系统加载可执行文件时,动态链接器(如 Linux 的 ld-linux.so)会同时加载其依赖的共享库(.so),解析符号并将库中函数的地址填入程序的内存映像中。这个过程在 main 函数执行之前完成。

  • 运行时链接(显式调用):程序运行时可以通过 dlopen()LoadLibrary() 等 API 主动加载动态库,并用 dlsym()GetProcAddress() 获取函数地址。此时链接发生在程序运行期间的任意时刻。

动态链接在编译时只做符号标记,真正的地址绑定发生在加载/运行时

静态链接是什么时候链的?

静态链接发生在编译/链接阶段

    动静态库对比:

    1.动态库形成的可执行程序体积一定很小,
    2.可执行程序对静态库的依赖度小,动态库不能缺失
    3.程序运行,需要加载内存,静态链接的,会在内存中出现大量的重复代码
    4.动态链接,比较节省内存和磁盘资源

gcc默认动态链接

那么如果静态链接呢?

静态链接,前提要有C静态库

显示缺失C库

   安装 glibc 的静态库版本

        sudo yum install -y glibc-static

为了便于区分把名字命名成code-static

可以很明显地看到动静态的大小相差巨大,动态小,静态大

不是一个动态可执行

如果是C++呢?

先安装g++

sudo yum install gcc-c++ -y

找不到静态库

安装C++静态库

sudo yum install libstdc++-static

    动态库的本质:
    是把语言层面公共的代码,在内存中只出现一次

sudo

再提一遍

普通用户

无权限

su -切换root用户进入/etc/sudoers

如果去掉这个user1,普通用户有些权限用不了。所以给重新加进来

技术上理解一下库

5.gcc其他常用选项 - 了解即可

• -E 只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面

• -S 编译到汇编语言不进行汇编和链接

• -c 编译到目标代码

• -o 文件输出到文件

• -static 此选项对生成的文件采用静态链接

• -g 生成调试信息。GNU 调试器可利用该信息。

• -shared 此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库.

• -O0

• -O1

• -O2

• -O3 编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高

• -w 不生成任何警告信息。

• -Wall 生成所有警告信息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值