计算机只能执行二进制的指令
翻译环境:在这个环境中,源代码被转换为可执行的机器指令(二进制指令)
执行环境:用于实际执行代码
我们创建了 test.c 文件,在里面写了一段 c语言源代码
点击生成解决方案,生成了可执行程序
test.c 依赖翻译环境,翻译成 test.exe VS2022是集成开发环境,集成了翻译环境
编译又分为3个小过程
一个项目会有多个 .c文件,每个源文件单独经过编译器处理,生成目标文件( Windows 上后缀为 .obj )
多个目标文件 + 链接库,通过链接器的链接最后生成可执行程序(链接库就是库函数的提供方)
我们增加一个文件
// test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
extern int Add(int x, int y);
int main()
{
int x = 0;
int y = 0;
scanf("%d %d", &x, &y);
int ret = Add(x, y);
return 0;
}
// add.c
#define _CRT_SECURE_NO_WARNINGS 1
int Add(int x, int y)
{
return x + y;
}
目标文件和源文件是对应起来的
一. 详解编译+链接
VS不方便演示,用 gcc编译器 使用命令的方式演示
1. 预处理
gcc -E test.c -o test.i 停止在预处理完成阶段,output 生成 test.i 文件
1. #include 头文件的包含
2. #define 定义符号的替换和删除
3. 注释的删除
都是文本操作
2. 编译
gcc -S test.i
把C语言代码翻译成了汇编代码
包含:语法分析、词法分析、语义分析、符号汇总
汇总的是全局符号(全局变量、函数名)
eg:test.c 文件 --> Add、main
add.c 文件 --> Add
3. 汇编
gcc -c test.c --> test.o (目标文件)
1. 把汇编代码翻译成了二进制指令(存放目标文件)
2. 形成符号表
eg:test.c add.c
test.c 里只有 Add 函数的声明,Add 函数的定义在 add.c 里。
所以符号表中,test.c 是 Add的无效地址 add.c 是 Add的真实地址
二进制指令我们看不懂,可以用工具:readelf
elf 是一种文件格式,一段一段的
4. 链接
1. 合并段表
2. 符号表的合并和重定位
上面2个符号表合并成这样:
如果代码有误,比如 add.c 里的 Add( ...... ) 写成 add( ...... )
汇编完成后的符号表:test.c add.c
合并符号表:
这时,test.c 里的 Add 还是无效地址,就报错 :"无法解析的外部符号 Add,函数 main 中引用了该符号"
二. C++中的函数重载
函数重载:C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型或 类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。
注:返回值没有要求
1. 参数类型不同
int Add(int left, int right)
{
cout << "int Add(int left, int right)" << endl;
return left + right;
}
double Add(double left, double right)
{
cout << "double Add(double left, double right)" << endl;
return left + right;
}
int main()
{
cout << Add(1, 2) << endl; // 3
cout << Add(1.1, 2.2) << endl; // 3.3
return 0;
}
2. 参数类型顺序不同
void f(int a, char b)
{
cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
cout << "f(char b, int a)" << endl;
}
int main()
{
f(1, 'a');
f('a', 1);
return 0;
}
3. 参数个数不同
void f()
{
cout << "f()" << endl;
}
void f(int a)
{
cout << "f(int a)" << endl;
}
int main()
{
f();
f(10);
return 0;
}
问题代码:
// 1、是否构成重载? -- 构成
// 2、问题:无参调用存在歧义
void f()
{
cout << "f()" << endl;
}
void f(int a = 0)
{
cout << "f(int a)" << endl;
}
int main()
{
f(); // 报错:“f”: 对重载函数的调用不明确
return 0;
}
三. C++支持函数重载的原理 - 名字修饰
C语言中,符号表的名字直接用的函数名 Linux 下 gcc
C++中,函数符号表,函数修饰后变成:_Z+函数长度 +函数名+类型首字母 Linux 下 g++
本篇的分享就到这里了,感谢观看,如果对你有帮助,别忘了点赞+收藏+关注。
小编会以自己学习过程中遇到的问题为素材,持续为您推送文章