初始C++入门(2)

news2024/12/24 2:40:47

缺省参数

缺省参数是 声明或定义函数时 为函数的 参数指定一个缺省值 。在调用该函数时,如果没有指定实
参则采用该形参的缺省值,否则使用指定的实参。
有句俗话叫,做人不能像缺省函数。
#include<iostream>
using namespace std;

void Func(int n=0)
{
	cout << n << endl;
}

int main()
{
	Func();
	Func(10);

}

那么缺省函数有什么作用呢? 

我们可以再次拿栈来举例,但我们不知道要往栈插入多少数据时,一般是#define数组大小,但这样不太好,因为数组大小给大了 浪费空间 数组大小给小了 空间不够,所以一般我们都是在堆上malloc开辟与指针结点大小一样的空间,再根据容量capacity相等否size数组大小进行扩容,但今天我们学了缺省函数以后就不用这样了!可以更加方便的插入一定的数据。

Stack.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<iostream>

typedef struct Stack
{
	int* a;
	int top;
	int capacity;
}ST;
void STInit(ST* ps,int n=4);
void STPush(ST* ps,int x);


test.cpp
#include"Stack.h"
void STInit(ST* ps, int n)
{
	//ps->a=NULL
	ps->a = (int*)malloc(sizeof(int) * n);
	ps->capacity = ps->top = 0;
}
void STPush(ST* ps, int x)
{
	//...
}
using namespace std;


int main()
{
	ST st;
	STInit(&st,100);
	for(size_t i=0;i<100;i++)
	{
		STPush(&st, i);
	}
	return 0;

}

但我们给缺省值时,我们可以根据自己的插入数据的个数来调差缺省值,比如我这边假设插入100个数据,就可以把n改成100,因为当我们给缺省值指定实参时,它会调用指定实参。

但缺省参数不能在函数的声明和定义同时给,会报错,所以祖师爷一般规定在声明给缺省参数值即可。缺省值必须是常量或者全局变量。

Stack.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<iostream>

typedef struct Stack
{
	int* a;
	int top;
	int capacity;
}ST;
void STInit(ST* ps,int n=4);
void STPush(ST* ps,int x);


test.cpp
#include"Stack.h"
void STInit(ST* ps, int n)
{
	//ps->a=NULL
	ps->a = (int*)malloc(sizeof(int) * n);
	ps->capacity = ps->top = 0;
}
void STPush(ST* ps, int x)
{
	//...
}
using namespace std;


int main()
{
	ST st;
	STInit(&st,100);
	for(size_t i=0;i<100;i++)
	{
		STPush(&st, i);
	}
	return 0;

}

全缺省函数

#include"Stack.h"

using namespace std;

void Func(int a=20,int b=30,int c=40)
{
	cout << "a= "<<a<< endl;
	cout << "b= " << b << endl;
	cout << "c= " << c << endl<<endl;
}

int main()
{
	Func();
	Func(10,2);
	Func(10, 20, 30);
    
//Func(,2,)//不能这样给

	
	return 0;

}

半缺省函数

void Func(int a=20,int b=30,int c)
{
	cout << "a= "<<a<< endl;
	cout << "b= " << b << endl;
	cout << "c= " << c << endl<<endl;
}

当我们传2个指定实参时会报红为什么呢?

 因为缺省值规定必须从右往左给 而且要连续给 全缺省也一样

报红是因为编译器认为2是给C的 那么10是给谁的?

所以从左往右传参会存在歧义。

为什么是从右往左给参数?因为在函数建立栈帧时,eax和ecx压栈时的传参也是先传右再传左进行压栈的

void Func(int a=20,int b,int c=30)
{
	cout << "a= "<<a<< endl;
	cout << "b= " << b << endl;
	cout << "c= " << c << endl<<endl;
}

这样也是一样的道理,必须从右往左传,必须连续,要不然一样会报红。

函数重载

自然语言中,一个词可以有多重含义,人们可以通过上下文来判断该词真实的含义,即该词被重载了。
比如:以前有一个笑话,国有两个体育项目大家根本不用看,也不用担心。一个是乒乓球,是男足。前者是“谁也赢不了!”,后者是“谁也赢不了!

提到中国足球,不得不提到昨天的国足1:2遭乌兹别克斯坦逆转...

函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。 

函数重载可以参数类型不同 函数名相同 返回值可同可不同

int ADD(int left, int right)
{
	cout << "int ADD(int left, int right)" << endl;
	return left + right;
}
int ADD(double left, double right)
{
	cout << "int ADD(double left, double right)" << endl;
	return left + right;
}

int main()
{
	ADD(1, 2);
	ADD(1.23, 1.34);


	
	return 0;

}

为什么这样写会报红呢?

因为double与 int 是可以完成隐式类型转换的  当这两个函数同时存在时会存在歧义,不知道调用哪个,当我们注释掉一个函数就可以调用了。

 参数不同

int f()
{
	cout << "f()" << endl;
}
int f(int a = 0)
{
	cout << "f(int a)" << endl;
}

两个构成函数重载,但在我们不传参时调用会存在歧义

当我们不给指定实参时,编译器不知道调用哪个,因为不传参值与指定实参值相同。

改成这样就ok了。

c

参数类型顺序不同 

void f(int a,char b)
{
	cout << "int f(int a,char b)" << endl;
	cout << a  <<endl<< b  << endl;
}
void f(char b,int a)
{
	cout << "int f(char a,int b)" << endl;
	cout << b << endl<<a  << endl;
}

int main()
{
	f(1 ,'x');
	f('x' ,3);

	
	return 0;

}

返回值有时候不能不同

一样会存在歧义,因为double和int能进行隐式类型转换。 

那为什么C++支持函数重载呢?而C语言不支持呢?

当我们有Func.h   func.cpp  test.cpp 三个文件时

在C语言编译链接中我们学过,一个程序要运行起来要经历4个阶段:预处理 编译  汇编 链接

预处理:头文件展开/宏替换/条件编译/去掉注释   Func.i  test.i

编译:检查语法/生成汇编代码         Func.s  test.s

汇编:转换成二进制的机器码         Func.o test.o

链接:合并到一起,链接一些函数还没有确定的等等    a.out

由于Windows下vs的修饰规则过于复杂,而Linux下g++的修饰规则简单易懂,下面我们使用了g++演示了这个修饰后的名字。但目前本人才疏学浅,只能简单演示下过程和原理,详细一步一步的调试等我再试炼试炼后,我再进行补充。

Linux下简单演示下过程和原理

在Linux中,在采用gcc(编译C语言文件)编译完成后,函数名修饰并没有发生改变。

采用g++(编译C++文件)编译

Linux函数名修饰规则
_Z   函数名字符个数   函数名   参数首字母
linux 下,采用 g++ 编译完成后,函数名字的修饰发生改变,编译器将函数参 数类型信息添加到修改后的名字中。
所以C语言在链接函数地址中,就会用函数名去找,但C语言不存在同名函数 不能构成函数重载。
通过这里就理解了C语言没办法支持重载,因为同名函数没办法区分。
C++ 是通过函数修 饰规则来区分
假设C++有两个函数名相同 参数类型不同的构成函数重载时
如果两个函数函数名和参数是一样的,返回值不同是不构成重载的,因为调用时编译器没办法区分

&引用

引用 不是新定义一个变量,而 是给已存在变量取了一个别名 ,编译器不会为引用变量开辟内存空
间,它和它引用的变量 共用同一块内存空间。
比如鲁迅又名周树人 李逵又名黑旋风
注意:引用类型必须和引用实体是同种类型的。

但这种引用的意义不大,引用最大的意义是做参数。 

那么引用和引用实体它们的地址相同不相同呢?

结果可以发现地址是相同的,因为引用没有开辟新的空间,只是引用实体的别名罢了。

 引用必须初始化

 总结

1. 引用在 定义时必须初始化
2. 一个变量可以有多个引用
3. 引用一旦引用一个实体,再不能引用其他实体

引用的价值

1.Swap交换函数

C语言写法

一般用传址给Swap函数,然后Swap函数开辟函数栈帧,进行数字之间的交换,再销毁,再返回给寄存器。

C++写法

直接使用引用,使用别名直接对实参a b本身修改,又不用开辟函数栈帧,也不用传址 提高效率

教科书上链表的写法

一般C语言写法

我们为了修改一级指针就需要进行传址并用二级指针接受才能进行修改一级指针指向的内容

typedef struct SListNode
{
	struct ListNode* next;
	int val;
}SLNode;

void PushBack(SLNode** phead, int x)
{
	if (*phead == NULL)
	{
		*phead = newode;
	}
	else
	{
		tail->next = newnode;
	}
}

int main()
{
    SLNode *plist = NULL;
	PushBack(&plist, 1);
	PushBack(&plist, 2);

    return 0;
}

教科书上的写法

typedef struct SListNode
{
	struct ListNode* next;
	int val;
}SLNode,*PListNode;

void PushBack(PListNode& phead, int x)
{
	if (phead == NULL)
	{
		phead = newonode;
	}
	else
	{
		tail->next = newnode;
	}
}

int main()
{

    SLNode plist = NULL;
	PushBack(plist, 1);
	PushBack(plist, 2);
    return 0;
}

实际第一个typedef SLNode是把SListNode修改成了 SLNode

第二个typedef 是把struct ListNode的节点指针修改成了 *PlistNode

相当于C++中的引用 PlistNode& phead 。很多同学在还没学习的C++的时候,观察数据结构教材书或者自己网上买的数据结构中的链表这样写,不明白到底是什么意思,其实就是C++的引用。

但并不推荐这样写 因为不够直观 而且很多C语言学习者并没有学习过C++,导致学习者的会更加混淆指针的理解与降低学习兴趣。

推荐写法

typedef struct SListNode
{
	struct ListNode* next;
	int val;
}SLNode;

void PushBack(SLNode& phead, int x)
{
	if (phead == NULL)
	{
		phead = newonode;
	}
	else
	{
		tail->next = newnode;
	}
}

int main()
{
    SLNode *plist = NULL;
	PushBack(plist, 1);
	PushBack(plist, 2);


    returm 0;
}

引用做返回值

为什么会出现这种情况呢?

虽然做引用返回值结果是正常的,但引用返回值返回两次,第二次结果就不对了,第三次又返回了正常,这又是为什么呢?

当用引用做返回值返回n时,相当于是n的别名,当count函数的函数栈帧销毁,n也会随着销毁,那么返回的时候n的值就是随机值。

虽然说vs2019保留了n的值并且屏幕输出了1(VS优化和处理比较好) 但其他编译器就不一定了。

我们再来观察一个函数

虽然引用做返回值的结果是正常的

但ret的值依旧取决于编译器对这块调用函数栈帧的销毁

所以第一个ret 要么是3 or 随机值 第二个ret同理 要么是7 or 随机值  (取决于编译器)

结论:当出了作用域,返回对象就销毁了,不能使用引用返回,否则结果返回的值是不确定的

所以只要出了作用域并不会销毁的就可以使用引用返回

比如静态区的静态变量和全局变量 堆区上开辟的空间。

时间一去不复返,但空间可以重复利用,当Func1的函数栈帧销毁以后,Func2再去建立函数栈帧利用空间是相同的。

引用做返回值——静态变量

因为静态变量出了Add函数作用域还存在and不会被销毁,且静态变量只会被初始化一次

所以当调用第一次Add函数值为3 第二次调用的值不变还是3

静态变量只初始化一次 所以第一次调用n=3,第二次调用Add 代码会一步一步执行就会被改变

因为相当于赋值 值为7。

传值和传引用效率的比较


做参数比较
做返回值比较

通过上述代码的比较,发现传值和指针在作为传参以及返回值类型上效率相差很大

链表修改pos位置的值

为什么这里可以用引用做返回值,因为出了作用域链表里面的ps->a不会销毁,因为是在堆上空间开辟的,没有free是不会销毁的,因此可以在链表修改pos的值时使用引用返回修改对象。

引用的常引用(权限问题)

 

引用可以权限的平移 权限的缩小 但不能权限的放大。

开头我讲的引用和引用实体类型必须相同就是这个道理

因为当double&d=i时,int 和double会存在隐式类型转换,产生一个临时变量,而临时变量具有常属性,不能被修改,所以double&d=i是错误的。但加上const造成权限的缩小就可以引用。

引用和指针的区别

可以从反汇编看出来 虽说引用语法不开空间 但底层是开发了空间的。

所以说语法与底层相反的 在底层实现上引用实际是有空间的,因为引用是按照指针方式来实现的。

内联函数

在讲内联函数之间,需要先提一下#define宏,因为内联函数继承了宏的优点且优化了宏的缺点。

宏的缺点:1.不能调试 2.容易出错,语法细节多(比如define ADD函数时必须要加双括号,否则会出现优先级问题,导致数值进行错误相加) 3.没有类型安全的检查

什么是内联函数?

inline 修饰 的函数叫做内联函数, 编译时 C++ 编译器会在 调用内联函数的地方展开 ,没有函数调
用建立栈帧的开销,内联函数提升程序运行的效率。

我们通过汇编来观察内联函数是否展开

但是debug环境下一般是写完代码然后去寻找错误的,所以在debug去查看汇编的时候,默认情况是没有在调用的时候去展开的 默认情况下确实没有展开 还是有call 说明还是会建立栈帧。

 要在debug查看内联函数展开要进行以下设置

点击项目名称右键查看属性

当设置完成后再次调试打开反汇编查看

改完属性发现call消失了 说明了内联函数展开了并且不用建立函数栈帧空间。

内联函数声明和定义不能分离

最好的方法就是声明和定义绑定

inline函数的特性

1. inline 是一种 以空间换时间 的做法,如果编译器将函数当成内联函数处理,在 编译阶段,会
用函数体替换函数调用 缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运
行效率。
2. inline 对于编译器而言只是一个建议,不同编译器关于 inline 实现机制可能不同 ,一般建
议:将 函数规模较小 ( 即内联函数定义代码行数不是很长,具体没有准确的说法,取决于编译器内部实现 ) 是递归、且频繁调用 的函数采用 inline 修饰,否则编译器会忽略 inline 特性。
3. inline 不建议声明和定义分离,分离会导致链接错误。因为 inline 被展开,就没有函数地址
了,链接就会找不到

《C++prime》第五版关于inline的建议:
内联说明只是向编译器发出的一个请求,编译器可以选择忽略这个请求。
般来说,内联机制用于优化规模较小、流程直接、频繁调用的函数。很多编译器都不支持内联递归函数,而且一个75行的函数也不大可能在调用点内联地展开。

这个代码行数是不固定的 取决于编译器。

这个时候代码就没有展开了。

这个内联函数 假设有100行 func函数 调用10000次

展开是100*10000次  不展开是100+10000(10个func函数+10000call func)

影响可执行程序的大小 比如游戏更新 安卓手机比苹果手机慢

比如更新一次版本,安卓用户:王者荣耀需要更新1GB多 苹果用户:王者荣耀只需要更新400多MB即可。苹果的底层原理是比较优越的。

范围的for循环

一般写数组

对于一个 有范围的集合 而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因
C++11 中引入了基于范围的 for 循环。 for 循环后的括号由冒号 分为两部分:第一部分是范
围内用于迭代的变量,第二部分则表示被迭代的范围

 

auto关键字

auto是一个关键字,可以自动识别变量的类型,也能代替特别长的类型名称

auto 意义定义对象时,类型较长,用它比较方便。

auto关键字暂且了解这么点即可。

指针空值nullptr

C语言之父发明C语言语法的时候,犯了一个错误就是把NULL 定义成宏#define NULL 0

C++之父为了弥补这个语法错误,就发明了C++中nullptr指针空值

我们本想通过f(NULL)调用f(int*),但结果却是两个int。

程序本意是想通过 f(NULL) 调用指针版本的 f(int*) 函数,但是由于 NULL 被定义成 0 ,因此与程序的
初衷相悖。
在C++98 中,字面常量 0 既可以是一个整形数字,也可以是无类型的指针 (void*) 常量,但是编译器
默认情况下将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转 (void
*)0

NULL实际是一个宏,在传统的C头文件(stddef.h)中,可以看到如下代码:

为了不与程序出现冲突,C++之父引进了nullptr关键字。

nullptr注意事项

1. 在使用 nullptr 表示指针空值时,不需要包含头文件,因为 nullptr C++11 作为新关键字引入
2. 在 C++11 中, sizeof(nullptr) sizeof((void*)0) 所占的字节数相同。
3. 为了提高代码的健壮性,在后续表示指针空值时建议最好使用 nullptr

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1119137.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C# winform如何实现数据的保存和读取

在c#winform中我们在写程序时&#xff0c;经常需要进行数据处理&#xff0c;那么数据如何保存和读取&#xff08;下面我们通过序列化和反序列化的方式来实现&#xff09; 第一步: 我们建立一个winform窗体 第二步: 构建一个外部实体类&#xff08;Student类&#xff09; 第…

再谈String

文章目录 一、字符串常量池1.1 创建对象的思考1.2 字符串常量池(StringTable)1.3 再谈String 对象创建 一、字符串常量池 1.1 创建对象的思考 下面创建String对象的方式相同吗&#xff1f; public static void main(String[] args) {String s1 "hello";String s2…

Java日志系统之Slf4j

目录 Slf4j Slf4j的简单使用 Slf4j的日志绑定流程 Slf4j桥接器 Slf4j Slf4j又称简单日志门面&#xff0c;Slf4j主要是为了给Java日志访问提供一套标准&#xff0c;规范的API框架&#xff0c;其主要意义在于提供接口&#xff0c;具体的实现可以交由其他的日志框架。 Slf4j…

概念解析 | 心脏电活动和机械活动之间的关系

注1:本文系“概念解析”系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:心脏电活动和机械活动之间的关系。 心跳的交响乐:心脏电活动与机械活动之间的关联 一、背景介绍 心脏通过不断跳动将血液输送到我们身体的每一个角落。而这个跳动过程,是…

【Godot】【BUG】4.x NavigationAgent 导航不生效

4.2.beta2 试了半天才发现原来默认只对第一个有导航的 TileMap 的第 1 层 生效&#xff0c;而我设置的导航层不是第一层&#xff0c;然后我新建了一个 TileMap 将导航的瓦片设置到这个 TileMap 上了&#xff0c;如图 这样就解决了问题&#xff0c;不用再修改默认设置的东西了&a…

超详细 | 差分进化算法原理及其实现(Matlab/Python)

差分进化(Differential Evolution&#xff0c;DE)算法是由美国学者Storn和 Price在1995年为求解Chebyshev多项式拟合问题而提出的。算法主要通过基于差分形式的变异操作和基于概率选择的交叉操作进行优化搜索&#xff0c;虽然其操作名称和遗传算法相同&#xff0c;但实现方法有…

英语——词根篇——单词——f

文章目录 31 . factfactdo,make做&#xff0c;作&#xff08;fact也作fac&#xff09; 32.ferferbring&#xff0c;carry带&#xff0c;拿 33 . florflorflower花&#xff08;flow也作flour&#xff09; 34 . flufluflow流 35 . fusfaus pour灌&#xff0c;流&#xff0c;倾泻 …

IOS屏幕旋转监听

1.设计窗口,添加三个按钮 2.添加事件连接 3.按钮点击事件实现 先添加三个IBAction 实现IBAction 使用旋转立刻生效 -(IBAction)btnFixPortrait:(id)sender{//访问应用程序委托成员_app.mask UIInterfaceOrientationMaskPortrait;//设置窗口旋转属性[self setNeedsUpdateOf…

有效管理token,充分发挥ChatGPT的能力

目录 给提供了 Token 的计算工具,来理解一下Token的计算方式,网址如下: 窗口如下: 实际消耗 Token 数量为 59个,换算之后为2.1-2.2的比例,即一个汉字消耗2.12.2个Token, 再测一下英文的Token消耗,包含空格在内,一共52个英文字母,消耗Token 13个,正好对应13个单词,…

Linux中shell外壳,用户权限,文件权限

Linux 权限 1.shell外壳1.1 shell外壳的定义1.2 shell外壳的作用1.3 shell的原理 2.Linux用户权限2.1创建普通用户2.2 用户之间的切换2.3 sudo指令 3.Linux文件权限3.1文件访问者的分类&#xff08;人&#xff09;3.2 文件文件类型和访问权限&#xff08;事物属性&#xff09;3…

1.3 矩阵

一、向量与矩阵 下面是三个向量 u \boldsymbol u u、 v \boldsymbol v v、 w \boldsymbol w w&#xff1a; u [ 1 − 1 0 ] v [ 0 1 − 1 ] w [ 0 0 1 ] \boldsymbol u\begin{bmatrix}\,\,\,\,1\\-1\\\,\,\,\,0\end{bmatrix}\kern 10pt\boldsymbol v\begin{bmatrix}\,\,\,…

洛谷p1618三连击

import java.util.Scanner; //将 1-9 共9个数分成3组&#xff0c;分别组成3个三位数&#xff0c;且使这3个三位数构成A:B:C的比例&#xff0c;试求出所有满足条件的3个三位数。不满足输出“No!!!”。 public class Main {public static void main(String[] args) {Scanner sc …

Linux_Shell运行原理(命令行解释器)

一般我们叫Linux操作系统&#xff0c;狭义上就是指Linux内核&#xff08;kernel&#xff09;&#xff0c;广义上就是Linux内核Linux外壳程序对应的配套程序&#xff0c;这里我们来详细介绍一下这个“外壳程序”。 在我们使用指令时&#xff0c;这个外壳程序会将我们的解释指令并…

从零开始学习 Java:简单易懂的入门指南之网络编程(三十七)

网络编程 1. 网络编程入门1.1 网络编程概述1.2 网络编程三要素1.3 IP地址1.4 InetAddress1.5 端口和协议 2.UDP通信程序2.1 UDP发送数据2.2UDP接收数据2.3UDP通信程序练习2.4UDP三种通讯方式2.5UDP组播实现2.6UDP广播实现 3. TCP通信程序3.1TCP发送数据3.2TCP接收数据3.3TCP程序…

什么是BFC(块级格式化上下文)?如何创建一个BFC?

BFC,即块级格式化上下文(Block Formatting Context),是CSS中的一个概念,用于描述页面中块级元素如何布局、定位和相互影响的一种机制。BFC是一个独立的渲染区域,具有一定的规则来决定其中元素的排布方式。 创建一个BFC主要有以下几种方法: 1:根元素()自动创建BFC:…

IDEA 新版本设置菜单展开

使用了新版本的IDEA 新UI后&#xff0c;常用的file&#xff0c;view&#xff0c;菜单看不见了&#xff0c;不太适应&#xff0c;找了一下&#xff0c;有个配置可以修改。 打开settings里面把show main menu in a separate toolbar勾选上&#xff0c;应用保存就可以了

Muse 2获取实时脑电数据

Muse 2获取实时脑电数据 之前转载了一篇知乎大佬汇总的采集Muse数据的博客&#xff0c;从亚马逊中国刷到了一个Muse 2&#xff0c;看了下不到2000块&#xff0c;于是果断下单。。。 历时一个月终于到了。。。 试用 需外网才能获取冥想音频资源&#xff0c;然后才能采集数据…

[0xGame 2023 公开赛道] week3

9点停止提交&#xff0c;抓紧时间写出来&#xff0c;明天还有别的题。 PWN edit-shellcode-runtime 可以输入shellcode然后执行&#xff0c;但是禁用了\x0f\x05(syscall&#xff0c;箭头处)&#xff0c;这里需要用前边的程序把这个syscall弄出来。我这里最后一个字符输入\x0f…

Node学习笔记之Node简介

一、Node简介 1.1、为什么学习Node(了解) 企业需求 增加自身职业竞争力 进一步理解 Web&#xff0c;并有助于明白后端开发 大前端必备技能 为了更好的学习前端框架 ... ... 1.2、Node是什么 Node.js是基于 Chrome的V8 JavaScript 引擎构建的JavaScript运行环境。 Node.js不是新…

C++特性——inline内联函数

1. 内联函数 1.1 C语言的宏 在C语言中&#xff0c;我们学习了用#define定义的宏函数&#xff0c;例如&#xff1a; #define Add(x, y) ((x) (y)) //两数相加相较于函数&#xff0c;我们知道宏替换具有如下比较明显的优点&#xff1a; 性能优势&#xff1a; 宏在预处理阶段…