C/C++ 程序员的基本素养 - 编译+链接

计算机只能执行二进制的指令
翻译环境:在这个环境中,源代码被转换为可执行的机器指令(二进制指令)
执行环境:用于实际执行代码

我们创建了 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++

本篇的分享就到这里了,感谢观看,如果对你有帮助,别忘了点赞+收藏+关注
小编会以自己学习过程中遇到的问题为素材,持续为您推送文章

评论 26
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值