linux下gcc的编译过程和功能,预处理,编译,汇编,链接,.c预处理为.i文件.s文件.o文件.exe文件

linux下gcc的编译过程和功能,预处理,编译,汇编,链接,.c预处理为.i文件.s文件.o文件.exe文件
2022找工作是学历、能力和运气的超强结合体,遇到寒冬,大厂不招人,此时学会c++的话,
我所知道的周边的会c++的同学,可手握10多个offer,随心所欲,而找啥算法岗的,基本gg
提示:系列c++学习的基础和高阶知识,用于公司生产实践中,实实在在的公司部署产品要用的,因为c++速度快,
而java和Python速度慢,自然往硬件里面部署算法啥的,都得用c++或者c,因此本科学的c很重要,后来的Python或者java就没有那么重要了,
c/c++系列文章:
【1】c++:c语言优缺点,visual studio2019如何新建项目,写hello world程序
【2】c/c++:gcc安装,gcc编译hello world文件,system函数调用系统命令,sleep函数
文章目录
- linux下gcc的编译过程和功能,预处理,编译,汇编,链接,.c预处理为.i文件.s文件.o文件.exe文件
-
- @[TOC](文章目录)
- c/c++:linux下gcc的编译过程
- 复习
- gcc预处理做了什么?
- gcc编译做了什么?
- gcc汇编做了什么?
- gcc链接做了什么?
- 高度总结gcc四个步骤
- 总结
文章目录
- linux下gcc的编译过程和功能,预处理,编译,汇编,链接,.c预处理为.i文件.s文件.o文件.exe文件
-
- @[TOC](文章目录)
- c/c++:linux下gcc的编译过程
- 复习
- gcc预处理做了什么?
- gcc编译做了什么?
- gcc汇编做了什么?
- gcc链接做了什么?
- 高度总结gcc四个步骤
- 总结
c/c++:linux下gcc的编译过程
上一节课,我写过hello.c将其编译成可执行文件

这是windows10下的过程
实际上,gcc的编译过程分别是4个步骤:
预处理
编译
汇编
连接

预处理hello.i【参数-E】
编译hello.s【参数-S】
汇编hello.o【二进制机器代码文件,目标文件】【参数-C】
连接hello.exe【可执行文件】【无参数】
命令是:

我们要把下面这个过程分解为四步

gcc -E gan.c -o gan.i

gcc -S gan.i -o gan.s

gcc -C gan.s -o gan.o

最后
gcc gan.o -o gan1
这步骤我没有成功
但是呢
就这四个步骤,你得熟悉

预处理,编译,汇编,连接
复习

系统头文件<>
""是自定义头文件
std标准库io是输入输出库
void最好是写,没有输入参数
可以不写,也是无参数
main必须有,程序中必须有,且只有一个,表示程序启的入口
//单行注释
//多行注释,块注释
f();函数调用完事冒号结束
{}函数主体,到此完事
return 0;程序正常结束
如果程序其他的还需要停止就需要调用系统函数system(“系统命令”);
windows.h文件别忘了哦,不会查百度

整个代码文件需要是.c结束的文件哦
这是c
c++才是后面的东西
visual studio可以编译c文件
你当然也可以用txt文件写,改为.c后缀
用gcc编译即可
sleep是休眠函数,休眠多少ms吧
gcc预处理 -E 生成.i文件【预处理文件】
编译 -S 生成.s文件【汇编文件】
汇编 -c 生成目标文件.o【目标文件】
连接 无参数 生成可执行文件.exe【可执行文件】
反正四个步骤,你可以浓缩为一个步骤即可
好说
待会我们继续讲
gcc预处理做了什么?

gcc预处理 -E 生成.i文件【预处理文件】
gcc -E hello.c -o hello.i

参数别忘记了哦
.i是预处理文件哦
我们去看看.i文件,是啥东西?
预处理完成的是,头文件展开的工作
把头文件里面的内容,整体给你展开,方便咱们main函数后续使用头文件的各种函数

你去看看hello.i文件,里面和hello.c的区别就是
hello.i的头文件一大堆,后面的代码和.c文件一样的
所以预处理处理的就是头文件。
不检查语法错误哦。
可以展开任意文件,但是错误不错误不知道。
在c语言中,.h就行,它不管,只看是否为.h文件即可。
咱们如果里面不写.h,而是写别的后缀文件
比如写一个hello.x

你再预处理试试
D:\\AWYY\\leetcode\\cplus\\test>gcc -E hello.c -o hello2.i
hello.c:2:10: fatal error: xxx.x: No such file or directory#include "xxx.x" //用户自定义的^~~~~~~
compilation terminated.
gg了看到了吗
完成任务终止
失败了呗
但是这无大碍,因为我们没有xxx.x文件啊
它报错是因为没有这个文件
如果有呢?
咱们加上文件


你在编译试试
D:\\AWYY\\leetcode\\cplus\\test>gcc -E hello.c -o hello2.iD:\\AWYY\\leetcode\\cplus\\test>
成功了
然后你看看hello2.i
里面是啥
# 1 "hello.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "hello.c"# 1 "xxx.txt" 1
111122223333
# 3 "hello.c" 2int main(void)
{printf("调用cmd命令");system("pause");}
你看看,预处理干了什么?
不就是把这txt头文件内部的东西给导入到我这个文件里面了吗?
所以,懂了没,gcc预处理就是第一步,把头文件导入,我估计python的import就是这个意思也是要导入的头文件的,那些函数我们需要用。
但是不查错的哦。
它还做这些事情哦

然后修改.c代码为
#include<stdio.h>
//#include "xxx.txt" //用户自定义的#define PI 3.14 //宏定义常量PIint main(void)
{printf("hello world\\n");printf("d%", PI); //打印PI
}
你再编译时时
D:\\AWYY\\leetcode\\cplus\\test>gcc -E hello.c -o hello2.iD:\\AWYY\\leetcode\\cplus\\test>
看看.i文件什么情况
# 6 "hello.c"
int main(void)
{printf("hello world\\n");printf("d%", 3.14);
}
发现了啥?
PI变3.14了
所以说预处理,直接将宏定义的常量直接用常量替换了。
即宏名替换为宏值
另外,你看看,那些注释跑哪里去了????
没了
相当于将注释直接废掉,用空字符替代了
这也是预处理的功能之一
美滋滋。
还有,展开条件编译,怎么说呢
#include<stdio.h>
//#include "xxx.txt" //用户自定义的#define PI 3.14 //宏定义常量PIint main(void)
{printf("hello world\\n");printf("d%", PI); //打印PI#ifdef PI
printf(1);//如果上面定义了PI,则打印1
#endif
}
编译试试
D:\\AWYY\\leetcode\\cplus\\test>gcc -E hello.c -o hello2.iD:\\AWYY\\leetcode\\cplus\\test>
# 6 "hello.c"
int main(void)
{printf("hello world\\n");printf("d%", 3.14);printf(1);}
因为PI定义了,所以一定要打印
条件编译
这种就预处理也要搞的事情。
懂?
还有一些预处理要干的事情,现在先了解到现在就可

gcc编译做了什么?
编译 -S 生成.s文件【汇编文件】

咱们直接将hello.i
用命令编译
D:\\AWYY\\leetcode\\cplus\\test>gcc -S hello.i -o hello.s
hello.c: In function 'main':
hello.c:7:2: warning: implicit declaration of function 'system' [-Wimplicit-function-declaration]{^
编译之后的文件叫做汇编文件
汇编语言写的文件,顾名思义
.file "hello.c".text.def __main; .scl 2; .type 32; .endef.section .rdata,"dr"
.LC0:.ascii "\\265\\367\\323\\303cmd\\303\\374\\301\\356\\0"
.LC1:.ascii "pause\\0".text.globl main.def main; .scl 2; .type 32; .endef.seh_proc main
main:pushq %rbp.seh_pushreg %rbpmovq %rsp, %rbp.seh_setframe %rbp, 0subq $32, %rsp.seh_stackalloc 32.seh_endprologuecall __mainleaq .LC0(%rip), %rcxcall printfleaq .LC1(%rip), %rcxcall systemmovl $0, %eaxaddq $32, %rsppopq %rbpret.seh_endproc.ident "GCC: (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 7.3.0".def printf; .scl 2; .type 32; .endef.def system; .scl 2; .type 32; .endef
这些都是汇编指令
汇编是连接c语言和机器指令的语言
所以:gcc编译的过程,就是将c语言汇编为汇编语言
如果代码有错误,无法汇编成功
生成失败就会删除那个代码
汇编的功能之一就是逐行检查代码的正确性。这是整个编译过程中最耗时的。

gcc汇编做了什么?
汇编 -c 生成目标文件.o【目标文件】

现在的话,我们就要汇编了
将s文件,生成为目标文件.o
D:\\AWYY\\leetcode\\cplus\\test>gcc -c hello.s -o hello.o
注意,参数是c哦
不是别的大C啥的,否则汇编不成功
txt打开是乱码了
实际上文件里面是二进制的机器指令

反正你要知道,这是目标文件即可
将汇编指令翻译为机器可以识别的二进制代码
因为机器才能认识那些指令,我们人是记不住的
因为记不住,才造出来汇编语言,汇编也麻烦,所以后来发明了c语言
c语言大家嫌麻烦,所以后来出现了c++和python,java等等等等
懂吧???
所以,高级语言在运行之前,需要把这些工作做好,然后一步步往下转
翻译为机器语言
gcc链接做了什么?
连接 无参数 生成可执行文件.exe【可执行文件】

okay,这波我们就可以去生成可执行文件了
D:\\AWYY\\leetcode\\cplus\\test>gcc hello.o -o hello
链接的目的:
数据段合并
数据地址回填
库引用


你在cmd里面运行hello.exe就可以运行了
D:\\AWYY\\leetcode\\cplus\\test>hello.exe
调用cmd命令请按任意键继续. . .D:\\AWYY\\leetcode\\cplus\\test>
懂了吧
gcc四个步骤,就这么来的
当然你可以一步到位
D:\\AWYY\\leetcode\\cplus\\test>gcc hello.c -o hello2D:\\AWYY\\leetcode\\cplus\\test>hello2.exe
hello worldD:\\AWYY\\leetcode\\cplus\\test>
但是你要知道gcc的4个步骤,一步一步都是怎么来的,懂?
高度总结gcc四个步骤

如果你用hello.c
直接用参数S,它就会跳过预处理阶段,直接生成汇编文件
直接用参数c,它就会跳过预处理和编译阶段,直接生成目标文件
直接不用参数,它就会跳过预处理,编译和链接,直接生成可执行文件
懂?

总结
提示:重要经验:
1)
2)学好c++,即使经济寒冬,手握10个大厂offer绝对不是问题!
3)笔试求AC,可以不考虑空间复杂度,但是面试既要考虑时间复杂度最优,也要考虑空间复杂度最优。


