IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> [C++] 内联函数inline 以及 auto关键字 -- C++入门(4) -> 正文阅读

[C++知识库][C++] 内联函数inline 以及 auto关键字 -- C++入门(4)

本篇文章主要包括内联函数和auto关键字。其中,内敛函数包括概念,特性等;auto关键字的使用规则,使用场景等。

目录

1.内敛函数

1.1问题引入:

1.2内联函数的概念

1.3内敛函数的特性

2.auto关键字

2.1auto简介

2.2 auto的使用细则

2.3 auto不能推导的场景

2.4 auto与新式for循环使用

1.内敛函数

1.1问题引入:

我们在使用C语言中我们都学过函数,我们知道函数在调用的过程中需要开辟栈帧。如果我们需要频繁的调用一个函数,假设我们调用10次Add()函数,那我们就需要建立10次栈帧。我们都知道在栈帧中要做很多事情,例如保存寄存器,压参数,压返回值等等,这个过程是很麻烦的。那在C语言中,我们可以通过宏来解决这个问题。在C++中,我们便引入了内敛函数(inline)。

1.2内联函数的概念

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

我们这里依然使用Add()函数举例。这段代码是我们常写的Add()函数。假设我们多次调用Add函数,在C语言中,我们可以使用宏替换。在C++我们可以在函数前加上inline

int Add(int x, int y)
{
	int z = x + y;
	return z;
}

C语言中用宏来代替Add函数:?

#define Add(x,y) ((x)+(y))

C++中在函数前加上inline使之成为内联函数

inline int Add(int x, int y)
{
	int z = x + y;
	return z;
}

那C语言已经有了宏替换,为什么C++还要出现内联函数呢?

主要是有两个原因:

1.宏晦涩难懂不好控制,特别容易写错.语法机制设计不好。

2.宏不支持调试,但是内敛在debug下支持调试(在debug下不会展开,在release下才会展开),这样我们对代码的理解和掌握将大大提高。

如果在Add函数前增加 inline 关键字将其改成内联函数,在编译期间编译器会用函数体替换函数的调用。
查看方式:
1. release 模式下,查看编译器生成的汇编代码中是否存在 call Add
2. debug 模式下,需要对编译器进行设置,否则不会展开 ( 因为 debug 模式下,编译器默认不会对代码进 行优化,以下给出 vs2019 的设置方式 )

?

?

1.3内敛函数的特性

1. inline 是一种 以空间换时间 的做法,省去调用函数额开销。所以 代码很长 或者有 循环 / 递归 的函数不适宜使用作为内联函数。
2. inline 对于编译器而言只是一个建议 ,编译器会自动优化,如果定义为 inline 的函数体内有循环 / 递归等等,编译器优化时会忽略掉内联。
3. inline 不建议声明和定义分离,分离会导致链接错误。因为 inline 被展开,就没有函数地址了,链接就会找不到
1.3.1 inline是一种以空间换时间的做法,省去调用函数额开销(建立栈帧).所以代码很长或者递归的函数不适宜用内联函数.

这里代码多长算长呢?? 一般是10行左右,具体取决于编译器。

1.3.2. inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等等,编译器优化时会忽略掉内联。

这里可以举个例子,假设我们有一个代码需要10行,但是我们需要调用1000次。如果inline替换的话,我们要有1000*10条指令,如果不替换则有1000+10条指令。因此最终是否替换,取决于编译器。

inline int Add(int x, int y)
{
	int z = x + y;
	z += x * y;
	z += x * y;
	z += x * y;
	z += x * y;
	z += x * y;
	z += x * y;
	z += x * y;
	z += x * y;
	z += x * y;
	z += x * y;
	z += x * y;
	return z;
}

我们发现,虽然Add函数前加了inline,但是最终却没有展开。

3. inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到

?我们在f.cpp中调用一下:发现报错了

?在这里他就会发生链接错误:

?这是因为test.h中替换到test.cpp中发现是内联函数,内联函数不需要生成地址,因为内联函数调用的地方都展开了,因此不会存在在符号表中。外部调用时就找不到。因此不要将声明和定义分开。

2.auto关键字

2.1auto简介

在早期 C/C++ auto 的含义是:使用 auto 修饰的变量,是具有自动存储器的局部变量。C++11中,标准委员会赋予了auto 全新的含义即: auto 不再是一个存储类型指示符,而是作为一个新的类型 指示符来指示编译器, auto 声明的变量必须由编译器在编译时期推导而得

auto在C语言中我们是接触过的:最宽宏大量的关键字,由于局部变量默认都是auto修饰的,因此auto可以省略,这就导致auto常常被人忽略。那么在C++11中,auto进行了升级,有了新的功能--自动推导。(注意:auto新功能只是在C++11之后才有此功能)

?那么auto是怎么自动推导呢?

我们可以使用typeid,来打印一个变量的类型。

int main()
{
    const int  a = 10;
	auto b = &a;
	auto c = 'a';

	cout << typeid(b).name() << endl;//typeid可以打印一个变量的类型
	cout << typeid(a).name() << endl;//typeid可以打印一个变量的类型
	cout << typeid(c).name() << endl;//typeid可以打印一个变量的类型

	return 0;
}

我们发现auto的自动推导还是很智能的。

auto意义之一:类型很长时,懒得写,可以让他自动推导

注意:

使用 auto 定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导 auto 的实际类 。因此 auto 并非是一种 类型 的声明,而是一个类型声明时的 占位符 ,编译器在编译期会将 auto 替换为 变量实际的类型

2.2 auto的使用细则

1. auto与指针和引用结合起来使用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&.
int main()
{
	int x = 10;
	auto a = &x;
	auto& c = x;
	cout << typeid(x).name() << endl;//typeid可以打印一个变量的类型
	cout << typeid(a).name() << endl;//typeid可以打印一个变量的类型
	cout << typeid(c).name() << endl;//typeid可以打印一个变量的类型
	return 0;
}
2. 在同一行定义多个变量当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量
	auto a = 1, b = 2;
	auto c = 3, d = 4.0;//c和d类型不同,auto推导会冲突的

?

2.3 auto不能推导的场景

1. auto不能作为函数的参数

// 此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
void TestAuto(auto a)
{}

?

?2. auto不能直接用来声明数组

void TestAuto()
{
	int a[] = { 1,2,3 };
	auto b[] = { 4,5,6 };
}

2.4 auto与新式for循环使用

在平常我们打印一个array数组,我们需要依次打印遍历。如下代码所示:

int main()
{
	int array[] = { 1,2,3,4,5 };
	for (int i = 0; i < sizeof(array) / sizeof(int); ++i)
		array[i] *= 2;
	for (int i = 0; i < sizeof(array) / sizeof(int); ++i)
		cout << array[i] << " ";
	cout << endl;

	return 0;
}

我们也可以使用auto结合范围for循环打印这个数组:

	for (auto e : array)
		cout << e << " ";
	cout << endl;

在这里我们使用到了一个新的for循环,范围for。它会依次自动取array中的数据,赋值给e,并且会自动判断结束,因此我们使用auto可以自动识别数组元素的类型。

注意:e只是array的拷贝,改变e不会改变array数组的内容。如果我们想改变array的内容,只需要加个引用即可,意思是让e成为array的别名,代码如下:

	//加个引用就可以访问到array
	for (auto& e : array)
	{
		e /= 2;
	}
	for (auto e : array)
		cout << e << " ";

(本篇完)

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-14 09:47:23  更:2022-05-14 09:47:53 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/11 1:19:56-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码