C++入门:内联函数、auto关键字、基于范围for循环及指针空值nullptr
目录
一. 内联函数
1.1 内联函数的概念
1.2 内联函数的特性
1.3 内联函数和宏的优缺点对比
二. auto关键字(C++11)
2.1 auto的功能
2.2 auto在使用时的注意事项
三. 基于范围的for循环(C++11)
四. 指针空值nullptr(C++11)
一. 内联函数
1.1 内联函数的概念
内联函数,就是使用inline关键字,让C++编译器在调用函数的位置处将函数在开展被调用的位置,从而减少函数栈帧创建和销毁的时间。
内联函数的声明方法:inline 返回值类型 函数名(参数列表)。下面的代码以add函数为例,演示了内联函数的定义和声明的方法。
inline int add(int x, int y)
{return x + y;
}int main()
{int x = 10, y = 10;int ret1 = add(x, y);int ret2 = add(x, y);return 0;
}
- 在Debug模式下,内联函数默认不展开,但可以通过更改编译器设置,来让内联函数在Debug模式下也展开。
- 在Release版本下,内联函数展开。
知识拓展:Debug被称为调试版本,编译器不会对程序进行优化,但可以调试找bug。Release版本被称为发布版本,编译器会对程序进行优化,但是程序员不可以在Release版本下调试。
设置在Debug版本下内联函数展开的方法:
- 打开属性设置,选择C/C++ -> 常规,将调试信息格式改为程序数据库。
- 选择C/C++ -> 优化,将内联函数扩展改为:只适用于_inline (Ob1)。

图1.2和1.3展示了使用内联函数的不使用内联函数时,调用add函数的汇编代码的区别。不使用内联函数时,调用add函数要先为通过call指令来跳转,建立函数栈帧后才会执行函数中的指令。使用inline时,汇编语言中不再有call指令,函数的指令直接展开在主函数中。


1.2 内联函数的特性
内联函数是一种以空间换时间的方法
C++内联函数类似于宏,都是在使用的位置展开,从而减少函数栈帧创建和销毁的开销。假设,一个函数(func)编译完成后有10条汇编指令,调用这个函数1000次,使用内联和不使用内联的情况下,汇编指令的条数为:
- 不使用内联函数:1000 + 10次,call func() 1000次 + 10条函数指令。
- 使用内联函数:1000*10次,每次调用展开函数,每次调用都需要独立的10条指令。
inline对于编译器来说只是建议,展不展开最终由编译器决定
这一点和register寄存器关键字类似,register关键字的功能是建议将变量存储在寄存器,仅仅是建议,到底要不要将变量放在寄存器由编译器决定而不是register。
- 对于比较长(指令较多)的函数,即使不进行展开,创建函数栈帧的开销相对于执行函数指令很小,编译器很可能就不展开。
- 递归函数不适用于inline,因此,对于存在递归调用的函数,即使使用inline进行声明,编译器也不会展开函数。
inline声明和定义不能分离
由于inline会直接在调用函数的位置处展开,在编译阶段生成的符号表中不会存储函数的地址,因此,如果定义和声明分离,则会存在找不到函数的问题,这样会发生链接错误。下面的代码在头文件中使用inline声明sub函数,在func.c文件中定义函数,报错。
//head.h
#include<iostream>
using namespace std;
inline int sub(int x, int y);//func.cpp
#include "head.h"
inline int sub(int x, int y)
{return x - y;
}//test.cpp
#include "head.h"
int main()
{int x = 10, y = 10;int ret1 = sub(x, y);int ret2 = sub(x, y);return 0;
}

总结:内联函数与宏类似,适用于函数代码量少且频繁被调用的场景。
1.3 内联函数和宏的优缺点对比
内联函数和宏共有的优点:
- 省去了函数栈帧的创建消耗,提高了代码的效率。
内联函数和宏共有的缺点:
- 代码量变大
内联函数相对于宏的优点:
- 可读性好,读内联函数与读普通函数无明显区别。
- 宏本质上是替换,不可以调试,而内联函数在Debug模式下默认不展开,可以进行调试。
- 宏没有类型检查,而内联函数有类型检查。
下面的代码就会报警告:从“double”转换到“int”,可能丢失数据
int add(int x, int y)
{return x + y;
}int main()
{double x = 10, y = 10;int ret1 = add(x, y);int ret2 = add(x, y);return 0;
}
二. auto关键字(C++11)
2.1 auto的功能
在C++98和C++03的标准中,auto关键字的作用是使变量出了定义变量的作用域就自动销毁,但是,在默认情况下,变量都是具有auto属性的且出了定义变量的作用域就会自动销毁。因此,在早期的C++标准下,auto关键字没有任何实质性意义。
C++11标准中,auto被赋予了全新的功能,摒弃了C++98和C++11原来的作用。auto的新功能为:自动推断类型。
下面的代码中通过auto来声明变量类型,再通过typied().name来打印类型。typeid().name()获取类型时,经常会省去const。
int main()
{int a = 10;char c = 'a';auto a1 = a;auto a2 = c;auto a3 = 10;auto a4 = 'a';auto a5 = 12.345;//typeid().name() 能够自动识别变量(常量)类型并实现对变量类型的打印//但是,使用typeid获取类型很多时候会舍去constcout << typeid(a1).name() << endl;cout << typeid(a2).name() << endl;cout << typeid(a3).name() << endl;cout << typeid(a4).name() << endl;cout << typeid(a5).name() << endl;//auto类型数据在定义是就必须初始化,因为编译器要通过判断其被初始化的数据的类型来判断auto的类型//auto a6; //编译不通过return 0;
}
如果定义const int a = 10,在使用auto b = a将a的值赋给b,这时b是可以被修改的,auto不会将a的const属性带给b。如果希望b不能被修改,则应当使用const auto b = a。
int main()
{const int a = 10;auto b = a;cout << b << endl;b = 30;cout << b << endl;//const auto b = a; //这时b具有只读const属性//b = 40; //报错return 0;
}
2.2 auto在使用时的注意事项
1、在使用auto声明变量是必须初始化
auto是根据变量被初始化的数据类型来推断变量类型的,如果不初始化,那么就无法确定auto是什么类型的数据,编译会报错。
int main()
{int a = 10;auto b;return 0;
}

2、使用auto在同一行声明多个变量时,类型必须相同
编译器只会对第一个变量的类型进行推导,用推导出来的类型定义后面的变量。
int main()
{auto a = 10, b = 20; //编译通过auto c = 20, d = 12.23; //编译报错
}
3、auto不能做为函数的类型
auto需要通过被初始化的数据来推断,而函数形参类型没有初始化,无法推断函数具体的参数类型。
void func(auto x)
{cout << "void func(auto x)" << endl;
}int main()
{func(10);return 0;
}

4、auto不能直接用来声明数组
这里不需要纠结原因,明确不用auto声明数组就好。
int main()
{int a[] = { 1,2,3 };//auto a1[] = { 1,2,3 }; //编译报错return 0;
}
5、使用auto声明指针类型和引用类型
在声明指针类型时,auto*和auto没有任何区别,但使用auto声明引用类型时,就必须写为auto&,&不能丢。
int main()
{int a = 10;auto pa1 = &a; //auto获取指针类型auto* pa2 = &a; //auto*获取指针类型auto& ra = a; //使用auto定义a的引用cout << typeid(a).name() << endl; //intcout << typeid(pa1).name() << endl; //int *cout << typeid(pa2).name() << endl; //int *cout << typeid(ra).name() << endl; //int *pa1 = 20; //a = 20;*pa2 = 30; //a = 30;ra = 40;cout << &a << endl;cout << &ra << endl; //&a和&ra相同return 0;
}

三. 基于范围的for循环(C++11)
在之前使用C语言的时候,要打印数组中的每个元素,我们需要获取数组元素的个数,通过for循环来实现,就有了下面的代码。但是,普通for循环sizeof(arr)/sizeof(arr[0])使用起来相对复杂,有更简单的方法吗?当然有。
int main()
{int arr[] = { 1,2,3,4,5 };for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); ++i){printf("%d ", arr[i]);}return 0;
}
在C++11标准中,给出了基于范围的for循环语法,语法格式为:for(auto x : arr),其实现的功能为:将arr数组中的数据依次赋给x,直到数组的最后一个元素,每一个数据赋给x表示一层循环。下面这段代码使用基于范围的for循环,打印数组中的每个数据。
int main()
{int arr[] = { 1,2,3,4,5 };for (auto x : arr){cout << x << " ";}cout << endl;return 0;
}
不需要程序员去计算数组中元素个数,这里编译器会自动处理。同时,有两点注意事项:
- auto x : arr中的x可以被替换为i、j等任意名称。
- auto可以被替换为int,但是,如果数组元素的类型发生变化,就需要更改int,因此最好直接声明为auto。
那么,如何通过基于范围的for循环修改数组中元素的值呢?这里就需要引用。
int main()
{int arr[] = { 1,2,3,4,5 };for (auto& a : arr){a += 1; //数组每个元素+1}for (auto x : arr){cout << x << " ";}cout << endl;return 0;
}

看到这里,可能会有疑惑:引用在有了引用实体之后,就不能再引用其他实体,那么为什么for (auto& a : arr)不存在改变引用实体的问题呢?答:每一层for循环结束后,变量a都会被销毁,进入下一层循环时,a是再次创建,而不是更改以前的引用实体,所有不存在问题。
四. 指针空值nullptr(C++11)
在C++03、C++98和C语言中,使用NULL来表示指针空值。我们可以看到,C++头文件中对NULL的定义如下:
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
也就是说,在C++中,NULL只是将NULL定义为值为0的宏,并没有将其转化为指针类型,所以,NULL存在类型不明确问题。为了解决C++98和C++03中NULL类型冲突的问题,C++11引入了新的指针空值nullptr,其定义为:#define nullptr ((void *)0) -- 将0强转类型转化为void*类型。
下面代码定义了一组函数重载,两个func函数的参数分别为int类型和int*类型,如果传入NULL调用func,我们希望调用的函数为func(int*),但实际上是func(int)被调用了,这是因为NULL被替换为了0,从而误调用了func(int),而传入nullptr就不存在问题。
void fun(int x)
{cout << "void fun(int x)" << endl;
}void fun(int* x)
{cout << "void fun(int* x)" << endl;
}int main()
{//C++98、C++03int* p1 = NULL;int* p2 = 0; //会与数字0发生冲突//C++11int* p3 = nullptr;fun(NULL); //void fun(int x)fun(nullptr); //void fun(int* x)return 0;
}

相关文章:

C++入门:内联函数、auto关键字、基于范围for循环及指针空值nullptr
目录 一. 内联函数 1.1 内联函数的概念 1.2 内联函数的特性 1.3 内联函数和宏的优缺点对比 二. auto关键字(C11) 2.1 auto的功能 2.2 auto在使用时的注意事项 三. 基于范围的for循环(C11) 四. 指针空值nullptr(…...

Python遗传算法
1 人工智能概述 2020中国人工智能产业年会在苏州召开,会上发布的《中国人工智能发展报告2020》显示,过去十年(2011-2020) ,中国人工智能专利申请量达389571件,占全球总量的74.7%,位居世界第一。 报告指出,…...

GEE学习笔记 六十四:绿色中国报告(个人版)
2019年上半年在遥感圈里最火的一篇文章莫过于这篇《China and India lead in greening of the world through land-use management》(China and India lead in greening of the world through land-use management | Nature Sustainability),…...

【Kubernetes】【十八】数据存储 高级存储 配置存储
高级存储 PV和PVC 前面已经学习了使用NFS提供存储,此时就要求用户会搭建NFS系统,并且会在yaml配置nfs。由于kubernetes支持的存储系统有很多,要求客户全都掌握,显然不现实。为了能够屏蔽底层存储实现的细节,方便用…...

传输层TCP与UDP协议
目录 传输层 传输层功能 传输层所提供的服务 传输层的两个协议 TCP协议与UDP协议 端口 端口分类 IP地址和端口的关系 UDP协议 前言: UDP报文格式 检验和的伪首部 伪首部内容 TCP协议 TCP报文格式 TCP协议数据段的理解 TCP的伪首部 伪首部内容 标…...
字节数组的通俗解释
1.字节是通过网络传输信息(或在硬盘或内存中存储信息)的单位。2.在ASCII码中,一个英文字母(不分大小写)占一个字节的空间,一个中文汉字占两个字节的空间。注意:utf-8码中一个汉字占三个字节&…...

硬件学习 软件Cadence day06 原理图网表导入PCB (过程和操作的错误),开始的画板
1.新建一个制作芯片的工程 1.打开 File ->New 2.填写信息,设置路径 2.原理图的网表导入 1.打开这个窗口 File -> import ->Logic.. 2.确定信息 3.解决网表导入时出现的错误 1. 第一个案列 (没有找到文件 也是这个) 比如说: WARNING(…...

OCT 医学图像分类
目录1. OCT 图像分类2. OCT图像数据集3. OCT图像预处理4. 特征提取5. 实验结果及分析github地址: https://github.com/aishangcengloua/OCT_Classification 1. OCT 图像分类 视网膜光学相干断层扫描(OCT)是一种成像技术,用于捕获活体患者视网膜的高分辨率横截面。…...
华为OD机试 - 合并数组 | 机试题算法思路 【2023】
最近更新的博客 华为OD机试 - 简易压缩算法(Python) | 机试题算法思路 【2023】 华为OD机试题 - 获取最大软件版本号(JavaScript) 华为OD机试 - 猜字谜(Python) | 机试题+算法思路 【2023】 华为OD机试 - 删除指定目录(Python) | 机试题算法思路 【2023】 华为OD机试 …...
前端开发页面样式通用约定法则
代码组织 以组件为单位组织代码段;制定一致的注释规范;组件块和子组件块以及声明块之间使用一空行分隔,子组件块之间三空行分隔;如果使用了多个 CSS 文件,将其按照组件而非页面的形式分拆,因为页面会被重组,而组件只会被移动;良好的注释是非常重要的。请留出时间来描述…...

向上跳空缺口选股公式,选出回补后再启动的标的
一、向上跳空缺口选股公式 思路:先找出缺口,缺口前后有两根K线,缺口低价是前一根K线的最高价,缺口高价是后一根K线的最低价。(如上图)收盘价低于缺口低价,即实现缺口回补。回补缺口之后…...

【IoT】做短视频之前,你需要先做好内容定位
现在做内容无疑要从垂直领域入手,否则你就很难出圈。 干货类或者说垂直领域方向的内容,往往都偏向于枯燥,并且会涉及很多专业性的名词,读者理解起来会困难很多,阅读的兴趣也自然会降低。 这也是笔者个人开始做短视频…...

苏宁基于 AI 和图技术的智能监控体系的建设
汤泳,苏宁科技集团智能监控与运维产研中心总监,中国商业联合会智库顾问,致力于海量数据分析、基于深度学习的时间序列分析与预测、自然语言处理和图神经网络的研究。在应用实践中,通过基于 AI 的方式不断完善智能监控体系的建设&a…...

3、内存管理
文章目录1、内存的基础知识1.1、什么是内存?1.2、进程的运行原理--指令1.3、逻辑地址 & 物理地址1.4、从写程序到程序运行1.5、装入模块到运行1.6、装入的三种方式--绝对装入1.7、装入的三种方式--静态重定位1.8、装入的三种方式--动态重定位(重定位…...

【蓦然回首忆Java·基础卷Ⅰ】
文章目录开端通过引用创建对象Java的数据存储方式基本类型包装类和高精度数字操作符自动递增和自动递减老生常谈的问题:和equals()如何重写equals方法?短路字面量科学计数法位运算类型转换初始化和清理方法的重载方法的重写无参构造器this与构造器垃圾收…...
类属性和对象属性
6.3 类属性和对象属性 在类定义中,属性按照归属分为对象属性、类属性。按照调用的私密性分为一般属性和私有属性。 6.3.1 类属性和对象属性 对象属性是最常用到的一种属性。即使我们对上面的类:MyClass1实例化了一个mc的对象,mc对象也不能…...

【TensorFlow 】查看Tensorflow和python对应版本、将现有的TensorFlow更新到指定的版本
1、查看Tensorflow和python对应版本 1.1这里我是在TensorFlow官方网址产看的 1、打开官方网址 https://pypi.org/project/tensorflow/1.1.0rc2/#files但是这个网址好像打不开,点击会出现这样 问题不大 输入Tensorflow然后点击搜索,就会跳转到https://p…...

VO、DTO、BO、PO、DO区别
VO、DTO、BO、PO、DO区别 VO:(View Object)视图对象,一般位于Controller层,用于展示视图。DTO:(Data Transfer Object)数据传输对象, 即RPC 接口请求或传输出去的对象&a…...

速看!!!一套能直接拿捏大厂面试官的软件测试面试宝典
3.5.1、说说你们是怎么做自动化测试的☆☆☆☆☆我们的自动化测试主要是web UI的自动化测试,主要用于冒烟测试和主要功能的回归测试或者主流浏览器的兼容性测试,作为手工测试的一种补充,提高测试效率,减少一些重复性的测试工作。1…...

超级完整 的 Maven 讲解 以及私服搭建
第一章 Maven 简介 1.1、Maven 概述 Maven 是一款基于 Java 平台的项目管理和整合工具,它将项目的开发和管理过程抽象成一个项目对象模型(POM)。开发人员只需要做一些简单的配置,Maven 就可以自动完成项目的编译、测试、打包、发…...

网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序
一、开发环境准备 工具安装: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 项目初始化: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...