Linux开发工具——gcc

📝前言:

这篇文章我们来讲讲Linux开发工具------gcc:

🎬个人简介:努力学习ing

📋个人专栏:Linux

🎀CSDN主页 愚润求学

🌄其他专栏:C++学习笔记,C语言入门基础,python入门基础,C++刷题专栏


目录

一,背景知识

一份代码变成一个可执行程序的步骤:预处理→编译→汇编→链接

具体了解步骤可看C语言的编译和链接

简单介绍每个过程的步骤:

  • 预处理 :宏替换,删除注释,头文件展开,条件编译处理。生成.i文件(还是C语言文件),相当于一个代码裁剪想过程。
  • 编译 :生成.s文件,文件内容变成汇编语言
  • 汇编 :生成.o目标文件,内容是机器语言(虽然是机器语言了,但是不能直接运行,因为预处理的头文件展开只是展开函数声明,此时缺乏链接操作,无法找到函数调用的地址)

二,gcc/g++

gcc和g++的区别是:gcc只能处理C语言,g++即可以处理C也可以处理C++。

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

如,执行:gcc code.c -o code.exe:

-o指明目标文件,目标文件要紧跟在-o后面。如果没有就默认生成a.out

三个选项:

  • -E:预处理完就停止,预处理结果输出到终端
  • -S:编译完就停止,生成一个后缀为.s的汇编文件
  • c:汇编完就停止,生成一个后缀为.o的目标文件

执行:

  1. gcc -E code.c > code.i
  2. gcc -S code.c
  3. gcc -c code.c

结果:

那么现在我们继续探讨几个问题:

1. 条件编译的作用

条件编译是在编译过程中根据特定条件来决定是否对某些代码块进行编译的一种机制。【这意味着可以实现对代码的动态裁剪】

如,不同的操作系统和硬件平台可能有不同的特性和要求,使用条件编译可以根据当前的编译环境选择不同的代码进行编译,从而使程序能够在多个平台上正常运行。(无序写多份代码)

c 复制代码
#include <stdio.h>

// 判断操作系统类型
#ifdef _WIN32
    #define PLATFORM "Windows"
#elif __APPLE__
    #define PLATFORM "Mac OS"
#elif __linux__
    #define PLATFORM "Linux"
#else
    #define PLATFORM "Unknown"
#endif

int main() {
    printf("This program is running on %s.\n", PLATFORM);
    return 0;
}

命令行级别的宏定义

方法:在gcc语句后加-D宏名[=宏值](若不指定宏值,默认为1)

如,code.c加宏定义#define M 100:

bash 复制代码
gcc  code.c -o code.exe -DM=100

如果在 code.c 中已经有 #define M 100,同时又使用 -DM=100 进行命令行宏定义,那么命令行的宏定义会覆盖源文件中的宏定义

2. 为什么要先编译成汇编语言

语言的发展是从:开关控制→打孔编程→汇编语言→高级语言

但是,编译的过程却是一个逆向的过程。

  1. 汇编语言和机器语言更接近
  2. 经过长时间的发展,汇编语言到机器语言已经有了一套方法,我们可以借助
  3. 从高级语言直接到机器语言会更复杂,不同的高级语言都实现这一过程,就太浪费已经有的汇编语言到机器语言的方法了。

3. 编译器的自举

我们需要用C语言编译器将C语言转换成汇编语言,那这个编译器是C语言实现的还是汇编语言实现的呢?

过程如下:

  1. 先用汇编语言写一个简单的C语言的编译器
  2. 然后用这个编译器编译一个用C语言写的更完整的C语言编译器的源代码,形成新的编译器
  3. 然后再用新生成的编译器再次编译自身的源代码,得到一个更新的编译器

不断重复这个过程,直到编译器达到满意的性能和稳定性。

三,动静态链接 初理解

命名规则

Linux中库的命名规则是:前缀lib + 库名称 + .so / .a后缀

  • Linux下:.so:动态库,.a:静态库
  • Windows下:.dll:动态库,.lib:静态库

如:C语言标准动态库就是:libc.so

ldd

对于可执行的文件对象使用ldd 文件名可以查看程序依赖的库。

链接

对于库函数printf,我们没有实现它,那代码是怎么运行的呢?

编译过程 :
gcc会把源代码转换为汇编代码,接着再转换为.o目标文件。在编译期间,编译器仅依据头文件中的声明来检查 printf 函数的使用是否正确,而不会去关心 printf 函数的具体实现。

链接过程:

静态链接:

链接器会将静态库中被目标文件引用的代码部分直接拷贝到可执行文件中。(有多少个printf就要拷贝多少份)

静态链接完成后,静态库在程序运行时就不再被依赖,可执行文件独立加载到内存中运行,静态库不会被加载。

动态链接:

链接器只会在可执行文件中记录所需动态库的名称和符号信息。(即不会将动态库的代码复制到可执行文件中)

运行时,可执行文件和动态库都会被加载到内存中。遇到库函数时,通过符号解析和重定位找到库函数,进入库里面的函数内部运行,运行完后返回原来的程序。

在这个过程中,动态库是一个共享库,被多个程序共享(公共代码在内存中只出现一次)。

动静态库对比:

  1. 动态库形成的可执行文件小
  2. 动态库可执行程序对动态库依赖大,不能缺失
  3. 静态链接的可执行文件中会有大量重复代码
  4. 动态库要加载到内存,但是总体上节省内存和磁盘资源

gcc 默认用动态链接,如果要使用静态,可加-static选项,如果没有对应的静态库,需要自行安装。

理解库

库其实就是打包起来的多个.o文件,里面有众多库函数/功能。

我们的程序生成.o文件后,在和库的.o文件链接,形成.exe。

我们通常习惯先形成多个.o文件,打包,然后再链接运行。(这样,当有一个文件修改时,就只需要要重新编译修改的那个文件,不需要整个项目全部重新编译)


🌈我的分享也就到此结束啦🌈

要是我的分享也能对你的学习起到帮助,那简直是太酷啦!

若有不足,还请大家多多指正,我们一起学习交流!

📢公主,王子:点赞👍→收藏⭐→关注🔍

感谢大家的观看和支持!祝大家都能得偿所愿,天天开心!!!

相关推荐
weixin19970108016几秒前
《淘宝TOP API:落地方案、接口边界与业务踩坑 —— 聚石塔内外价差 10 倍的真相》(附 Python 源码)
开发语言·python
前端 贾公子2 分钟前
LangGraph == 图的状态(State)管理 (上)
java·开发语言·数据库
skywalk81636 分钟前
在FreeBSD系统的linux仿真环境下安装和使用kiro 这个亚马逊的AI agent
linux·人工智能·freebsd·kiro
Mikko78 分钟前
Linux 磁盘满了但 du 找不到?LVM 扩容 df 不变?fstab 写错开不了机?三台真机实测磁盘排查
linux·运维·centos
yumgpkpm23 分钟前
Acceldata ODP 3.3.6.4 vs CDP Private Cloud Base 7.3.2 对比
大数据·运维·服务器·hadoop·华为·zookeeper·hbase
Madison-No727 分钟前
多语言聊天大模型--测试报告
linux·git·python·selenium·jmeter·自动化·postman
Liuqy-0533 分钟前
特殊进程——孤儿、僵尸、守护进程
linux·运维·服务器
流浪00143 分钟前
Linux系统篇47——线程(十二) POSIX 信号量与环形队列,把判空判满提前到访问之前
linux·操作系统·线程·信号量·环形队列
xuxigifxfh44 分钟前
牛客:HJ170 01序列
java·开发语言·算法·华为机考
朝朝辞暮i1 小时前
C++ 第 33 课:事件循环——spin() 到底在干什么
开发语言·c++·算法