【C++】内联函数vs宏 nullptr

news2024/9/23 13:21:59

目录

  • 宏的优缺点分析
    • 概念回顾
    • 宏的缺点
    • 宏的优点
  • 内联函数(inline)
    • inline函数的定义和声明
    • 总结

宏的优缺点分析

在这里插入图片描述

概念回顾

下面是宏的申明方式:

#define name( parament-list ) stuff
//其中的 parament-list 是一个由逗号隔开的符号表,它们可能出现在stuff中

例如:

#define SQUARE( x ) x * x
  • 这个宏接收⼀个参数 x .如果在上述声明之后,你把 SQUARE( 5 ); 置于程序中,预处理器就会⽤
    下⾯这个表达式替换上⾯的表达式: 5 * 5

注:① 参数列表的左括号必须与name紧邻,如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分。

相信很多人都忘了C语言阶段的宏。这时候定义一个宏形式就千奇百怪

//1.
#define Add(int x, int y)	return x + y;
//2.
#define ADD(x, y) x + y
//3.
#define ADD(x, y) (x + y)
//4.
#define ADD(x, y) ((x) + (y));
//5.
#define ADD(x, y) ((x) + (y))

  • 第一种肯定是不行的,这分明是函数的定义方式

后面四个的主要区别就在于后面的stuff,我们一一来分析一下

那第二个对了吗?
看看这个:

int ret = ADD(1, 2) * 3;

  • 可以观察到此时在预处理阶段也是直接进行了一个替换,不过仔细观察就可以发现,由于*的优先级来得高,所以2会和后面的3先进行一个运算,这也就造成了最后结果的不同
    在这里插入图片描述
  • 所以我们要在外层加上一个大括号防止出现优先级问题
#define ADD(x, y) (x + y)

  • 那这样就行了吗,如果我们向ADD函数这样传参呢?
int a = 10;  
int b = 20;
int ret = ADD(a | b, a & b);

  • 编译器还是一样会去做傻傻的替换,但是这个时候我们又得注意优先级的问题了,对于+号来说,它的优先级高于&按位与和|按位或的,
  • 所以中间的【b】和【a】会先进行结合,然后再去算&和|
    在这里插入图片描述
  • 如果要防止这种表达式传参出现优先级的问题,那么我们就应该为参数加上括号
#define ADD(x, y) ((x) + (y));

  • 最后这一种才是最正确的写法
#define ADD(x, y) ((x) + (y))		//✔

宏的缺点

  • 看了以上的代码,就知道宏有一个明显的缺点,定义太麻烦了,哪里都要加括号
  • 而且宏是不能像函数一样调试的,这样我们在写错宏的时候就很难排查哪里出了问题
  • 宏也没有类型的检查,无论我们传入那种类型的参数,都不会出问题,那么就会造成算术混乱

宏的优点

  • 宏提高了可复用性和可维护性,比如我们一般用到宏最多的地方就是把一个数字定义成一个宏,如一个数组我们刚开始想要是10个空间,但是后面不够,就可以直接更改宏来替换,不用一句句去改变
#define n 500

  • 宏不用创建函数栈帧,这就不会造成内存的消耗

内联函数(inline)

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

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

  • 但是他真的不会建立函数栈帧吗?

在这里插入图片描述

这里有call指令(call就是调用函数),调用了函数就会创建函数栈帧。难道是骗我们的?

  • 其实我们还需要去做一些配置
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 然后我们再去观察一下汇编就可以发现不存在call指令了,编译器直接将内敛函数Add做了展开
    在这里插入图片描述

  • 所以C++中我们是不推荐用宏的,因为有内联函数这个特性,即保留了宏的优点,无需调用函数建立栈帧,而且还修复了宏的缺陷,不再需要将内容写得那么复杂,写成日常的函数形式即可,只需要在前面加上一个inline关键字,就可以起到这种效果。非但如此,它还可以调试

  • vs编译器 debug版本下⾯默认是不展开inline的,这样⽅便调试

注意:vs的release版本是默认展开的

  • C++标准没有规定默认展开inline函数,是否展开这个函数取决于编译器本身,编程器通常只展开短小函数的内联函数(10行代码以内),不会对递归函数或者迭代展开
    在这里插入图片描述
  • 这其实就是内联函数在替代宏之后很优秀的一个特性,假设说现在你这个设置的内联函数有1000多行代码,在一个大项目中又有1000个地方调用了这个内联函数。
  • 如果采用内联将其展开的话消耗的就是1000 * 1000条指令

inline函数的定义和声明

  • inline不建议声明和定义分离到两个⽂件,分离会导致链接错误。因为inline被展开,就没有函数地址
    址,链接时会出现报错。
// F.h
#include <iostream>
using namespace std;

inline void f(int i);
//--------------------------
// F.cpp
#include "F.h"

void f(int i)
{
	cout << i << endl;
}
//--------------------------
// main.cpp
#include "F.h"

int main()
{
	f(10);
	return 0;
}

  • 解决这个问题就直接把定义和声明写到同一个头文件中

在这里插入图片描述
这样内联函数在展开的时候就可以找到地址

#nullptr

  • C++中NULL可能被定义为字⾯常量0,或者C中被定义为⽆类型指针(void*)的常量。不论采取何种
    定义,在使⽤空值的指针时,都不可避免的会遇到⼀些⿇烦,本想通过f(NULL)调⽤指针版本的
    f(int*)函数,但是由于NULL被定义成0,调⽤了f(int x),因此与程序的初衷相悖。f((void*)NULL);
    调⽤会报错。
#ifndef NULL
#ifdef __cplusplus
	#define NULL 0
#else
	#define NULL ((void *)0)
#endif
#endif

所以我们推荐在C++中使用nullptr代表空指针

总结

  • 引入内联函数的目的实际上就是为了补充C语言中宏的缺陷,如优先级问题,不能调试问题
  • 但是内联函数用的时候也要注意C++标准没有规定默认使用内联函数,取决于编译器。这种空间换时间的思想只适用于小型的函数,对于大型的函数不建议定义成【内联函数】,会造成程序的过多臃肿

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一个能够在网上爬取思维导图的python小程序

这个小程序是为需要从网上爬取思维导图的朋友写的,时间久了怕被遗忘在垃圾箱里,所以贴出来,给需要的同学使用。 河西石原创地址:https://haigear.blog.csdn.net/article/details/140878039 二、使用方法及流程介绍 简单的说明一下使用的方法: 1、在网上找到自己需要的思…

GBase8c psycopg2安装(centos6)

GBase8c psycopg2安装(centos6) 安装步骤&#xff1a; [rootcentos6 ~]# cd /opt/python/ [rootcentos6 python]# ls psycopg2-2.7.7.tar.gz [rootcentos6 python]# tar -zxf psycopg2-2.7.7.tar.gz [rootcentos6 python]# cd psycopg2-2.7.7 # 安装命令 [rootcentos6 psycop…

【C++:jsoncpp库的配置CMAKE的安装】

CMAKE的安装&#xff1a; 安装路径&#xff1a;Download CMake安装就是无脑Next跳出以下窗口以上步骤完了之后&#xff0c;页面如此&#xff0c;然后点击generate jsoncpp库的配置&#xff1a; 打开生成的源文件所在路径&#xff0c;找到名为jsoncpp.sln的文件&#xff0c;以vs…

大数据信用报告怎么查?有哪些注意事项?

大数据信用对于有资金周转的人来说是比较重要的&#xff0c;主要由于大数据信用无形的被不少机构用于贷前风控&#xff0c;无论是机构要求的还是自查&#xff0c;提前了解大数据信用情况是常规操作&#xff0c;那大数据信用报告如何查询?有哪些需要注意的呢?本文详细为大家讲…

【Kubernetes】k8s集群的资源发布方式

目录 一.常见的发布方式 二.如何实现 1.滚动升级 2.蓝绿升级 3.实现金丝雀发布&#xff08;灰度发布&#xff09; 一.常见的发布方式 蓝绿发布&#xff1a;两套环境交替升级&#xff0c;旧版本保留一定时间便于回滚。优点 用户无感知&#xff0c;部署和回滚速度较快缺点 …

使用 Python 对雷达卫星 sar 图像进行降噪的三种方法

合成孔径雷达 (SAR) 图像广泛应用于各种领域(航空航天、军事、气象等)。问题是这种图像在其原始格式中受到噪点的影响。虽然这些图像通常也是沉重的文件,但从科学的角度来看,有效地对其进行去噪的任务似乎既具有挑战性,又在现实世界中非常有用。 卫星图像有两大类: 光学…

嵌入式C++、QML与MQTT:智能化农业灌溉管理系统设计思路(代码示例)

目录 一、项目概述 二、系统架构 三、环境搭建 1. 硬件环境 2. 软件环境 四、代码实现 1. 硬件端代码示例 2. 软件端代码示例 a. 后端代码&#xff08;Node.js MQTT&#xff09; b. 前端代码&#xff08;QML&#xff09; 五、项目总结 一、项目概述 随着全球对农业…

Xinference如何注册自定义模型

环境&#xff1a; Xinference 问题描述&#xff1a; Xinference如何注册自定义模型 解决方案&#xff1a; 1.写个model_config.json&#xff0c;内容如下 {"version": 1,"context_length": 2048,"model_name": "custom-llama-3"…

Java 中的缓冲流

字符流 前面学习的字节流和字符流都是基本流&#xff0c;其中字符流的底层其实已经在内存中创建了一个长度为8192的字节数组作为缓存区。而字节流中则是没有的。 在内存中增加缓冲区的目的是为了减少内存与硬盘的交互的次数&#xff0c;因为这一操作比较耗时。 下面是一个图…

PixelMaster - 图片像素化终极利器 !

PixelMaster 是将普通图像转变为令人惊叹的像素艺术杰作的终极工具。非常适合艺术家、设计师和像素艺术爱好者&#xff01; https://apps.apple.com/app/pixelmaster-image-pixelator/id6502478442 为什么选择 PixelMaster&#xff1f; • 自定义像素形状&#xff1a;选择或导…

【Linux修行路】进度条小程序

目录 ⛳️推荐 一、预备知识 1.1 回车换行 1.2 缓冲区 二、倒计时 2.1 注意事项 三、进度条 3.1 源代码 3.2 代码分析 3.2 实际使用场景 ⛳️推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家…

安卓基本布局(上)

文章目录 LinerLayout线性布局RelativeLayout相对布局根据父容器定位根据兄弟组件定位margin偏移padding填充 LinerLayout线性布局 以水平或垂直的方式来排列界面中的控件。 常用属性详细描述orientation布局中组件的排列方式。horizonta&#xff1a;水平&#xff1b;vertical…

GPT-4o mini模型:小型化AI解决方案的创新应用案例

文章目录 每日一句正能量前言开发者视角初步接触与性能评估集成与开发流程成本效益分析创新应用案例面临的挑战与解决方案社区贡献与经验分享未来展望 性能评估处理能力与响应速度准确性与可靠性多功能性与灵活性资源效率可扩展性与集成性用户定制与微调 结论 成本效益分析初始…

C语言基础知识之函数指针和指针函数

函数指针和指针函数 函数指针和指针函数指向函数的指针返回指针值的函数指针函数和函数指针的区别 问题1_1代码1_1结果1_1 函数指针和指针函数 指向函数的指针 用函数指针变量调用函数 可以用指针变量指向整型变量、字符串、数组&#xff0c;也可以指向一个函数。一个…

ctfshow-web入门-sql注入(web176-web180)

目录 1、web176 2、web177 3、web178 4、web179 5、web180 1、web176 1 order by 4-- 闭合后简单判断了下字段数是 3 测试联合查询注入&#xff0c;存在关键字的过滤&#xff0c;包括 select 和 union &#xff08;后面经过测试实际只过滤了 select&#xff09; 大小写绕…

常⻅CMS漏洞

常⻅CMS漏洞 ⼀&#xff1a;WordPress ​ WordPress是⼀个以PHP和MySQL为平台的⾃由开源的博客软件和内容管理系统。WordPress具 有插件架构和模板系统。截⾄2018年4⽉&#xff0c;排名前1000万的⽹站中超过30.6%使⽤WordPress。 WordPress是最受欢迎的⽹站 内容管理系统。全…

Linux网络之多路转接——实用的epoll

目录 一、高级IO 1.1 概念 1.2 五种IO模型 1.3 小结 二、多路转接的实用派 2.1 epoll 接口 2.1.1 epoll_create 2.1.2 epoll_ctl 2.1.3 epoll_wait 2.2 epoll 底层原理 2.2.1 epoll_ctl 2.2.2 epoll_wait 2.2.3 epoll_create 三、 epoll 类的编写 3.1 类的框…

大数据-64 Kafka 高级特性 分区 分区重新分配 实测

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

使用uwsgi部署Flask应用

前言&#xff1a;本人大四&#xff0c;研0&#xff0c;在24年暑假在杭州某互联网公司实习&#xff0c;本文用来记录自己在公司学到的东西。 uwsgi&#xff1a;uWSGI是一个Web服务器&#xff0c;它实现了WSGI协议、uwsgi、http等协议。Nginx中HttpUwsgiModule的作用是与uWSGI服…

集合的基本使用

数据和集合的区别 数组可以存储基本数据类型和引用数据类型。 但是&#xff0c;集合不可以直接存储基本数据类型&#xff0c;需要以包装类的方式进行存储&#xff0c;其可以存储引用数据类型。 ArrayList 成员方法 import java.util.ArrayList;/*** ClassName Test* author …