?作者简介:大家好,我是橘橙黄又青,一个想要与大家共同进步的男人😉😉
🍎个人主页:橘橙黄又青-CSDN博客
今天学习:浅学编译和链接内部实现原理
前提:本文是在gcc编译环境下学习,目前只是浅学习
在ANSI C的任何?种实现中,存在两个不同的环境。
?
如图:
.c文件生成可执行文件过程:
? 多个.c?件单独经过编译出编译处理?产对应的?标?件。? 注: 在Windows环境下的?标?件的后缀是 .obj ,Linux环境下?标?件的后缀是 .o? 多个?标?件和链接库?起经过链接器处理?成最终的可执?程序。? 链接库是指运?时库(它是?持程序运?的基本函数集合)或者第三?库。
gcc -E test.c -o test.i
? 将所有的 #define 删除,并展开所有的宏定义。? 处理所有的条件编译指令,如: #if 、 #ifdef 、 #elif 、 #else 、 #endif 。? 处理#include 预编译指令,将包含的头?件的内容插?到该预编译指令的位置。这个过程是递归进 ?的, 也就是说被包含的头?件也可能包含其他?件 。? 删除所有的注释? 添加?号和?件名标识,?便后续编译器?成调试信息等。? 或保留所有的#pragma的编译器指令,编译器后续会使?。
?
来我们看看.i文件是怎么生成的呢?
这里我们发现有700多行代码,没错这里面的都是#include<stdio.h>里面的全部函数?等定义
?输入指令生成test.i文件,文件名可以随便改.i文件为文件后缀就行,那我们举上面的两个例子
外部函数包含例子
代码:
test.c文件
#include<stdio.h>
#include "test.h"
int g_val = 2024;
int main()
{
printf("hehe\n");
printf("%d\n", g_val);
return 0;
}
test.h 文件
?
int Add(int x, int y) {
return x + y;
}
生成de.i文件里面的内容:
#denfinen的例子
预处理完之后MAX就变成1000,这都是在test.i文件里面完成的,所以说使用#define到后面是不利于调试的,因为调试是在.exe文件里面完成的,.i文件只是一个过渡阶段。使用后就删除了?。
2.2 编译
gcc -S test.i -o test.s
输入指令后。生成.s文件,.s文件是汇编指令。
array[index] = (index+4)*(2+6);
记号 | 类型 |
---|---|
array | 标识符 |
[ | 左方括号 |
index | 标识符 |
] | 右方括号 |
= | 赋值 |
( | 左圆括号 |
index | 标识符 |
+ | 加号 |
4 | 数字 |
) | 左圆括号 |
* | 乘号 |
( | 右圆括号 |
2 | 数字 |
+ | 加号 |
6 | 数字 |
) | 右圆括号 |
由语义分析器来完成语义分析,即对表达式的语法层?分析。编译器所能做的分析是语义的静态分 析。静态语义分析通常包括声明和类型的匹配,类型的转换等。这个阶段会报告错误的语法信息。
gcc -c test.s -o test.o
#include <stdio.h>
//test.c
//声明外部函数
extern int Add(int x, int y);
//声明外部的全局变量
int main()
{
int a = 10;
int b = 20;
int sum = Add(a, b);
printf("%d\n", sum);
return 0;
}
Add.c代码:
int g_val = 2022;
int Add(int x, int y)
{
return x+y;
}
如图:
?
第2点的全部知识点图解:
?