4. C++入门:内联函数、auto关键字、范围for及nullptr

内联函数

概念

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

对比C的宏

C语言不足:宏

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

int main()
{
	int ret1 = ADD(2, 3);  //((2)+(3))*5

	int a = 1, b = 2;
	int ret2 = ADD(a | b, a & b);  //((a | b)+(a & b))

	return 0;
}

宏的缺点:

  1. 容易出错,语法细节多
  2. 不能调试
  3. 没有类型安全的检查
inline int Add(int x, int y)
{
	int c = x + y;
	return c;
}

int main()
{
	int ret1 = Add(1, 2);
	int ret2 = ADD(1, 2);

	return 0;
}

用enum,const,inline替代宏
enum,const替代的是宏常量
inline替代宏函数

普通函数要建立栈帧,会有很多的消耗

内联函数的特点:

  1. 不用建立栈帧,会在调用的地方展开,没有函数调用栈帧的开销,提高了效率
  2. 克服了宏的缺点
  3. 可以调试
  4. 好写,语法简单
查看方式

Debug版本下
![[Pasted image 20240515101325.png]]

内联函数在默认情况下,没有去展开
![[Pasted image 20240515101839.png]]

在项目属性里将常规里的调试信息格式改为程序数据库
![[Pasted image 20240515101906.png]]

优化里的内联函数扩展改为只适用于_inline(/Ob1)
再进行调试
![[Pasted image 20240515102038.png]]

这是没有call了,不会建立栈帧

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

内联只适合于频繁调用的小函数,小于等于10行代码

指令影响编译好的可执行程序的大小
如果暴力地对100行的大函数内联展开
比如有10000个调用这个函数的地方
展开合计:100*10000行指令
如果展开,不需要call,有多少个调用的地方就展开多少次,假设调用的地方是1行指令,展开成100行指令
不展开合计:100+10000行指令
有10000个调用的地方,不展开,每次调用只有一行指令

内联函数声明定义分离
#pragma once
#include <iostream>
using namespace std;

inline void f(int i);
#include "Func.h"

void f(int i)
{
	cout << i << endl;
}
#include "Func.h"

int main()
{
	f(10);

	return 0;
}

内联函数不能声明和定义分离
如果分离在两个文件,会报错,发生链接错误
在编译的时候,发现函数和参数能匹配上,先过

#pragma once
#include <iostream>
using namespace std;

inline void f(int i);
void func();
#include "Func.h"

void f(int i)
{
	cout << i << endl;
}

void func()
{
	f(5);
}
#include "Func.h"

int main()
{
	//f(10);

	func();

	return 0;
}

调f不可以,调func可以
不可以直接调,可以间接调

调用f的时候需要找f的地址,因为编译的时候只有声明
链接的时候没有找到内联函数的地址
因为内联函数不会生成地址,或者生成的地址不会生成符号表
内联函数直接再调用的地方展开了,就不需要地址
所以会报错

在Test.cpp自己的文件里调的时候,不会到链接那一步去找
因为直接有声明和定义,在Func.cpp里面,直接拿定义就在这展开了

内联函数如果分离在.h和.cpp,就不能再其他文件去用
如果再其他文件去用会报错
只能在当前这个cpp文件里使用

内联函数最好不要声明和定义分离
这样不管在哪个文件都可以使用,声明和定义在同一个文件就不需要链接了,因为直接就能找到定义

auto关键字

随着程序越来越复杂,程序中用到的类型也越来越复杂,经常体现在:

  1. 类型难于拼写
  2. 含义不明确导致容易出错

是可以通过typedef给类型取别名
但是在编程时,常常需要把表达式的值赋值给变量,这就要求在声明变量的时候清楚地知道表达式的类型。然而有时候要做到这点并非那么容易,因此C++11给auto赋予了新的含义

auto简介

可以自己推导类型

int main()
{
	int a = 0;
	int b = a;
	auto c = a;
	auto d = &a;
	auto* e = &a;
	auto& f = a;

	cout << typeid(c).name() << endl;
	cout << typeid(d).name() << endl;
	cout << typeid(e).name() << endl;
	cout << typeid(f).name() << endl;

	return 0;
}

这里c就是int类型
typeid可以用来打印一个对象的类型
![[Pasted image 20240515132627.png|166]]

可以省略下面的类型的定义,使代码短一点点

#include <vector>
#include <string>

int main()
{
	vector<string> v;
	//vector<string>::iterator it = v.begin();
	auto it = v.begin();

	return 0;
}
注意
  1. 使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型。
  2. auto与指针和引用结合起来使用
    用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&
  3. 在同一行定义多个变量
    当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
  4. auto不能作参数,返回值也不支持
  5. auto的意义就是,定义对象时,类型较长,用它比较方便
  6. auto不能声明数组

范围for

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

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

	for (int* p = array; p < array + sizeof(array) / sizeof(array[0]); ++p)
		cout << *p << endl;
}

对数组进行遍历,C语言进行遍历,使用下标计算数组的大小,或者搞一个数组的指针去算,比较麻烦

int main()
{
	int array[] = {1, 2, 3, 4, 5};
	for (auto e : array)
	{
		cout << e << " ";
	}
	cout << endl;
	
	return 0;
}

![[Pasted image 20240522092615.png]]

会依次取数组中的值赋值给e
自动判断结束,自动++往后遍历
这里的auto虽然也可以输入实际的类型,但是用了auto,就算后面数组对象的类型变了,这里也不需要修改代码
注意:与普通循环类似,可以用continue来结束本次循环,也可以用break来跳出整个循环

int main()
{
	int array[] = {1, 2, 3, 4, 5};
	for (auto e : array)
	{
		e++;
		cout << e << " ";
	}
	cout << endl;
	for (auto e : array)
	{
		cout << e << " ";
	}
	cout << endl;
	return 0;
}

如果想对每个数据++一下
![[Pasted image 20240522093833.png]]

发现并没有真正++。
只是修改了e,没有修改了数组中的数值。
因为是依次取数组中的每个值赋值给e,e的改变不会影响数组里面。
要修改的话,要加个引用

int main()
{
	int array[] = {1, 2, 3, 4, 5};
	for (auto& e : array)
	{
		e++;
		cout << e << " ";
	}
	cout << endl;
	for (auto e : array)
	{
		cout << e << " ";
	}
	cout << endl;
	return 0;
}

![[Pasted image 20240522094114.png]]

使用条件
  1. for循环迭代的范围必须是确定的
    对于数组而言,就是数组中第一个元素和最后一个元素的范围;对于类而言,应该提供begin和end的方法,begin和end就是for循环迭代的范围。
  2. 迭代的对象要实现++和==的操作。

指针空值nullptr

void f(int)  
{  
	cout<<"f(int)"<<endl;  
}  
void f(int*)  
{  
	cout<<"f(int*)"<<endl;  
}  

int main()  
{  
	f(0);  
	f(NULL);  
	f((int*)NULL);
	
	return 0;  
}

函数参数只写形参的类型,没有写形参的变量
不会报错,实参传给形参,形参可以不要,不要的时候可以作形参的匹配
![[Pasted image 20240522103025.png]]

第一个调用的是int,第二个NULL也调用的是int
因为C++的库,在实现的时候NULL定义成了一个宏
NULL可能被定义为字面常量0,或者被定义为无类型指针(void*)的常量

#ifndef NULL  
#ifdef __cplusplus  
#define NULL 0  
#else  
#define NULL ((void *)0)  
#endif  
#endif

C++98中,字面常量0既可以是一个整形数字,也可以是无类型的指针(void*)常量,但是编译器默认情况下将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转(void*)0

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java中的HashSet类

一、HashSet类 实现了Set接口&#xff0c;无法存储重复元素 特点&#xff1a;元素位置无序、无索引、底层是HashMap 1、构造方法 内部是HashMap的构造方法 2、add方法 (1)元素在底层存储使用到了三种数据结构&#xff1a;hash数组、链表、树 (2)添加流程&#xff08;根据…

arcgis 10.6 工具栏操作error 001143 后台服务器抛出异常

arcgis 10.6 工具栏操作error 001143 后台服务器抛出异常 环境 win10arcgis 10.6 问题 执行定义投影要素转线出现 Error: 001143:后台服务器抛出异常&#xff08;差点重装10.6&#xff09; 如下图所示&#xff1a; 解决方法 通过在菜单工具条上单击地理处理 > 地理处…

计算机网络学习小结_数据链路层

数据链路和帧 帧&#xff1a;数据链路层传输基本单元。链路层将网络层传过来的数据构成帧发到链路上&#xff0c;并将发到链路层的帧取出数据交给网络层 数据报/分组/包&#xff1a;网络层传输基本单元 三个基本问题 即封装成帧、透明传输、差错检测 封装成帧 概念&#…

尽微好物:从0到10亿+的抖音电商的TOP1“联盟团长”,如何使用NineData实现上云下云

杭州尽微供应链是抖⾳平台⽉均带货10E的TOP1“联盟团⻓”&#xff0c;是字节跳动⼀级代理商&#xff0c;巨量千川指定服务商&#xff0c;拥有商品库9万&#xff0c;是⾏业领先的电商供应链平台&#xff0c;达⼈陪跑机构。 杭州尽微供应链以天猫、京东抖音电商业务为依托&#x…

29.IO流(了解)

1. C语言的输入与输出 ​ C语言中我们用到的最频繁的输入输出方式就是scanf ()与printf()。 scanf(): 从标准输入设备(键 盘)读取数据&#xff0c;并将值存放在变量中。printf(): 将指定的文字/字符串输出到标准输出设备(屏幕)。注意宽度输出和精度输出控制。C语言借助了相应的…

Python全栈自动化测试-Python基础08--循环结构-while

目录 前言 一、while循环 二、while条件 1.while条件--固定值 2.while条件-运算符 三、避免死循环 1.条件不为恒定值 2.条件为恒定值 2.1.避免死循环-continue 2.2.避免死循环-break 2.3.避免死循环-breakcontinue 总结 前言 在Python编程中&#xff0c;循环结构是…

安科瑞汽车充电桩防火限流式保护器灭弧保护

充电桩防火限流式保护器 短路过载保护 充电桩防火限流式保护器 短路过载保护可有效克服传统断路器、空气开关和监控设备存在的短路电流大、切断短路电流时间长、短路时产生的电弧火花大&#xff0c;以及使用寿命短等弊端&#xff0c;发生短路故障时&#xff0c;能以微秒级速度…

软件工程期末复习(5)可行性研究

可行性研究 可行性研究的任务 可行性研究的目的&#xff1a; 用最小的代价&#xff0c;在尽可能短的时间内确定问题是否能够解决。 可行性研究的实质&#xff1a; 就是一次压缩、简化了的系统分析和设计的过程。 可行性研究的路线&#xff1a; 分析和澄清问题定义&#…

​学者观察 | 从区块链应用创新看长安链发展——CCF区块链专委会荣誉主任斯雪明

导语 2024年1月27日&#xff0c;斯雪明教授在长安链发布三周年庆暨生态年会上发表演讲&#xff0c;认为在区块链发展过程中&#xff0c;不仅需要技术创新&#xff0c;同时需要有价值、有特色、有示范意义的应用创新。斯雪明教授介绍了国内区块链技术与应用发展的现状、趋势与挑…

1721jsp网上银行管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 网上银行管理系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统采用web模式&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;…

官宣:极海G32A1445汽车通用MCU通过TÜV莱茵ISO 26262 ASIL-B功能安全产品认证

2024年5月16日&#xff0c;极海宣布G32A1445汽车通用MCU正式通过德国TV莱茵ISO 26262 ASIL-B功能安全产品认证。 德国TV莱茵大中华区工业服务与信息安全总经理赵斌先生、德国莱茵TV助理大客户经理詹丽龙女士&#xff0c;珠海极海半导体有限公司总经理汪栋杰先生、副总经理曾豪…

如何检查 Linux 服务器是否遭受 DDoS 攻击

1. 写在前面 DDoS&#xff08;Distributed Denial-of-Service&#xff09;攻击是最常见的服务器安全威胁之一&#xff0c;攻击频率和强度逐年稳步上升。本文主要介绍如何通过资源监控和及时采取一些措施来缓解 DDos 攻击。 2. 什么是 DDoS 攻击&#xff1f; DDoS 是一种恶意…

安装和使用图像处理软件GraphicsMagick @FreeBSD

GraphicsMagick是一个用于处理图像的读取、写入和操作的工具软件。它被誉为图像处理领域的“瑞士军刀”&#xff0c;短小精悍&#xff0c;支持超过88种图像格式&#xff0c;包括DPX、GIF、JPEG、JPEG-2000、PNG、PDF、PNM和TIFF等。 GraphicsMagick的主要特点包括&#xff1a;…

【Java基础】集合(1) —— Collection

存储不同类型的对象: Object[] arrnew object[5];数组的长度是固定的, 添加或删除数据比较耗时 集合: Object[] toArray可以存储不同类型的对象随着存储的对象的增加&#xff0c;会自动的扩容集合提供了非常丰富的方法&#xff0c;便于操纵集合相当于容器&#xff0c;可以存储多…

echarts 图表tooltip扩展(适配移动端)

2024.5.16今天我学习了如何对echarts 图表tooltip进行自定义设置&#xff0c;效果如&#xff1a; 如果是日维度&#xff0c;需要展示对应的星期&#xff0c;以及用移动端去查看这个图表提示要显示在整个图表内&#xff0c;如果没有设置position会溢出图表&#xff0c;通用写法代…

OpenHarmony标准设备应用开发(二)——布局、动画与音乐

本章是 OpenHarmony 标准设备应用开发的第二篇文章。我们通过知识体系新开发的几个基于 OpenHarmony3.1 Beta 标准系统的样例&#xff1a;分布式音乐播放、传炸弹、购物车等样例&#xff0c;分别介绍下音乐播放、显示动画、动画转场&#xff08;页面间转场&#xff09;三个进阶…

.NET 分享一款Web打包和解压缩工具

01本文概要 在.NET部署环境中&#xff0c;利用IIS中间件开启对ASP的支持&#xff0c;可以实现许多强大的文件操作功能。特别是在一些需要进行预编译的情况下&#xff0c;通过上传ASP脚本&#xff0c;可以获得WebShell&#xff0c;从而方便地进行各种操作。本文将介绍一个名为S…

一文搞懂车载系统开发学习路线

前言 随着汽车技术的快速发展和智能化趋势的加强&#xff0c;车载信息娱乐系统已经成为现代汽车不可或缺的一部分。因此&#xff0c;车载软件市场正在迅速增长&#xff0c;这为Android应用开发提供了新的机会。恰好近年来大环境不是很理想&#xff0c;车载开发不失为Android应…

概率论统计——大数定律

大数定律 弱大数定律&#xff08;辛钦大数定律&#xff09; 利用切比雪夫不等式&#xff0c;证明弱大数定律 应用 伯努利大数定理&#xff0c;&#xff08;辛钦大数定理的推论&#xff09; 证明伯努利大数定理 注意&#xff1a;这里将二项分布转化成0,1分布来表示&#xff0c;…

电能表抄表软件是什么?

1.电能表抄表软件简述 电能表抄表软件是当代电力系统中不可或缺的一部分&#xff0c;它通过大数据技术性完成了远程控制抄表、数据库管理及其电费测算等服务&#xff0c;大大提高了工作效能并降低了人为失误。这类软件的诞生&#xff0c;促使供电公司可以实时监控系统与分析电…