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 就可以自动完成项目的编译、测试、打包、发…...
业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
C++.OpenGL (14/64)多光源(Multiple Lights)
多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...
jmeter聚合报告中参数详解
sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample(样本数) 表示测试中发送的请求数量,即测试执行了多少次请求。 单位,以个或者次数表示。 示例:…...
