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

内联函数

概念

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

对比C的宏

C语言不足:宏

#define ADD(x, y) ((x)+(y))int main()
{int ret1 = ADD(2, 3);  //((2)+(3))*5int 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。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenFeign高级用法:缓存、QueryMap、MatrixVariable、CollectionFormat优雅地远程调用

码到三十五 &#xff1a; 个人主页 微服务架构中&#xff0c;服务之间的通信变得尤为关键。OpenFeign&#xff0c;一个声明式的Web服务客户端&#xff0c;使得REST API的调用变得更加简单和优雅。OpenFeign集成了Ribbon和Hystrix&#xff0c;具有负载均衡和容错的能力&#xff…

期权策略交易怎么做?怎么选择期权策略?

今天期权懂带你了解期权策略交易怎么做&#xff1f;怎么选择期权策略&#xff1f;期权交易是一种金融衍生品交易方式&#xff0c;它给予购买者在未来特定时间内以特定价格购买&#xff08;或出售&#xff09;标的资产的权利。 期权策略交易怎么做&#xff1f; 配对看跌期权&am…

vue+springboot实现echarts数据图统计

①vue项目修改配置 安装依赖&#xff1a; npm i echarts -S 修改路由index.js&#xff1a; import Vue from vue import VueRouter from vue-router import Manager from ../views/Manager.vue // 解决导航栏或者底部导航tabBar中的vue-router在3.0版本以上频繁点击菜单报错…

00.OpenLayers快速开始

00OpenLayers快速开始 官方文档&#xff1a; 快速开始&#xff1a;https://openlayers.org/doc/quickstart.html 需要node环境 一、设置新项目 npm create ol-app my-app cd my-app npm start第一个命令将创建一个名为 my-app​ 的目录&#xff08;如果您愿意&#xff0c;…

Python筑基之旅-MySQL数据库(一)

目录 一、MySQL数据库 1、简介 2、优点 2-1、开源和免费 2-2、高性能 2-3、可扩展性 2-4、易用性 2-5、灵活性 2-6、安全性和稳定性 2-7、丰富的功能 2-8、结合其他工具和服务 2-9、良好的兼容性和移植性 3、缺点 3-1、对大数据的支持有限 3-2、缺乏全文…

前端面试:项目细节重难点问题分享

面试官提问&#xff1a;我现在给你出一个项目实际遇到的问题&#xff1a;由于后端比较忙&#xff0c;所以我们这边的列表数据排序需要前端最近实现&#xff0c;那你会怎么实现排序呢&#xff1f; 答&#xff1a;我的回答&#xff1a;确实&#xff0c;数据都是由后端实现的&…

正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-19讲 串口实验UART

前言&#xff1a; 本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM&#xff08;MX6U&#xff09;裸机篇”视频的学习笔记&#xff0c;在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。…

嵌入式硬件中PCB走线与过孔的电流承载能力分析

简介 使用FR4敷铜板PCBA上各个器件之间的电气连接是通过其各层敷着的铜箔走线和过孔来实现的。 由于不同产品、不同模块电流大小不同,为实现各个功能,设计人员需要知道所设计的走线和过孔能否承载相应的电流,以实现产品的功能,防止过流时产品烧毁。 文中介绍设计和测试FR4敷…

Windows系统安装OpenSSH使用VScode远程连接内网Linux服务器开发

文章目录 &#x1f4a1;推荐 前言1、安装OpenSSH2、VS Code配置ssh3. 局域网测试连接远程服务器4. 公网远程连接4.1 ubuntu安装cpolar内网穿透4.2 创建隧道映射4.3 测试公网远程连接 5. 配置固定TCP端口地址5.1 保留一个固定TCP端口地址5.2 配置固定TCP端口地址5.3 测试固定公网…

Nginx/阿里云/二级域名的配置和使用

阿里云域名解析配置如下&#xff1a; nginx配置如下&#xff1a; 访问地址&#xff1a; zhadmin.iotzzh.com image.png

Hotcoin Research | 市场洞察:2024年5月13日-5月19日

加密货币市场表现 目前&#xff0c;加密货币总市值为1.32万亿&#xff0c;BTC占比54.41%。 本周行情呈现震荡上行的态势&#xff0c;BTC在5月15日-16日&#xff0c;有一波大的拉升&#xff0c;周末为震荡行情。BTC现价为67125美元。 上涨的主要原因&#xff1a;美国4月CPI为3…

深度学习之基于YoloV5钢材微小缺陷检测系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景与目标 在钢材生产过程中&#xff0c;由于各种因素&#xff0c;钢材表面可能会出现微小缺陷&#xff…

C# OpenCvSharp 模拟生成车辆运行视频

C# OpenCvSharp 模拟生成车辆运行视频 目录 效果 项目 代码 下载 效果 项目 代码 using OpenCvSharp; using OpenCvSharp.Extensions; using System; using System.Diagnostics; using System.Drawing; using System.Windows.Forms; namespace OpenCvSharp_Demo { p…

海外云手机的运作原理和适用场景

海外云手机是一种基于云计算技术的虚拟手机服务&#xff0c;通过将手机操作系统和应用程序托管在远程服务器上&#xff0c;实现用户可以通过互联网连接来使用和管理手机功能&#xff0c;而无需实际拥有物理手机。以下是有关海外云手机的相关信息&#xff1a; 海外云手机的运作原…

树莓派3B+入门(无外设)

昨日刚到一块树莓派3B&#xff0c;甚是喜爱&#xff0c;然半宿未眠 1、下载 在官网先下载烧录文件https://www.raspberrypi.com/software/ 下载完毕打开&#xff0c;选择&#xff0c;根据自己板子型号定 操作系统用最新的就行&#xff0c;64位不太稳定 储存卡&#xff0c;需…

超声波清洗机哪家好一点?四款超一流超声波清洗机大盘点

在追求极致清洁和维护精密工具、设备及珍贵物品的时代&#xff0c;超声波清洗机显得尤为重要。不仅因其高效、快速的清洁效果&#xff0c;更因其能够触及传统手工清洁所不能及的微小缝隙。无论你是珠宝设计师、机械工程师、还是热爱生活的普通家庭用户&#xff0c;超声波清洗机…

C语言例题43、打印倒立金字塔

#include <stdio.h>void main() {int i, j;for (i 5; i > 0; i--) {for (j 5; j > i; j--) {//输出空格printf(" ");}for (j 2 * i; j > 1; j--) {//输出星号printf("* ");}printf("\n");} }运行结果&#xff1a; 本章C语言…

【高阶数据结构(四)】图的最短路径问题

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:高阶数据结构专栏⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多数据结构   &#x1f51d;&#x1f51d; 高阶数据结构 1. 前言2. 单源最短…

基于springboot实现大学生就业需求分析系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现大学生就业需求分析系统演示 摘要 信息数据从传统到当代&#xff0c;是一直在变革当中&#xff0c;突如其来的互联网让传统的信息管理看到了革命性的曙光&#xff0c;因为传统信息管理从时效性&#xff0c;还是安全性&#xff0c;还是可操作性等各个方面来讲…

移动端适配(rem,vw)+响应式布局

1.1视口标签&#xff08;逻辑分辨率和设备匹配&#xff09; 1.2二倍图&#xff08;防止失真&#xff09; 二、适配方案 一、rem 1.1媒体查询 1.2、引入js文件&#xff08;remflexble.js&#xff09; 1.2、less Less 是一种动态样式语言&#xff0c;它扩展了 CSS 的功能&#…