当前位置: 首页 > news >正文

C++_2_ inline内联函数 宏函数(2/3)

C++推出了inline关键字,其目的是为了替代C语言中的宏函数。

我们先来回顾宏函数:

宏函数 

现有个需求:要求你写一个Add(x,y)的宏函数。

正确的写法有一种,错误的写法倒是五花八门,我们先来“见不贤而自省也。”

// 实现⼀个ADD宏函数的常⻅问题
#define ADD(int a, int b) return a + b;
#define ADD(a, b) a + b;
#define ADD(a, b) (a + b)

分析:

第一种写法:宏函数不是函数,它是宏,在预处理阶段就替换成了目标内容。

第二种写法:还是错的,少括号,较第一种好一点—— 在于没加分号

第三种写法:还是不对,不过好多了,错在少括号。

正确写法:

// 正确的宏实现
#define ADD(a, b) ((a) + (b))

这个写对了,不过“知其然,亦要知其所以然”。

// 为什么不能加分号 ?
// 为什么要加外⾯的括号 ?
// 为什么要加⾥⾯的括号 ?
//为什么不能添加分号 ;
#define Add(a,b) ((a) + (b));
int main()
{int ret1 = Add(1,2);//意在实现1 + 2并将结果赋值给ret1cout << ret1 << endl;//意在打印ret1return 0;
}

运行截图:

 

好戏还在后头:

cout << Add(1,3) << endl;

我们在前面曾说到:cout 能够自动识别变量类型,这里报错是因为函数的结果是它识别不了了嘛。 非也非也:

宏在预处理阶段,会将Add(1,3)替换成后面的表达式:这里若多加了分号,这行代码就在分号处中断了,而作为二元操作符的 << 前面无操作对象 后面又有个endl;自然因为缺少参数(表达式)报错。

cout << ((1) + (3)); << endl;//预处理阶段被替换成了如此模样

所以,宏函数里分号是多余的:

#define Add(a,b)  ((a) + (b))
int main()
{cout << Add(1,3) << endl;//这才能输出4return 0;
}

运行截图:

// 为什么要加外⾯的括号?
#define Add(a,b)  (a) + (b)
int main()
{cout << Add(1, 3) * 2 << endl;//意图输出 8 (4*2)return 0;
}
//替换后
//cout << Add(1, 3) * 2 << endl;
cout << (1) + (3) * 2 << endl;//然而据分析,输出7 (1+6)

 运行截图:

可见,外面括号是为了不改变运算表达式的结合的优先级,我们写个宏函数Add本意就是为了先算加法。

// 为什么要加⾥⾯的括号?
#define Add(a,b)  (a + b)
int main()
{int x = 1, y = 2;Add(x & y, x | y);//不加内括号,替换成 (x&y + x|y)return 0;
}
//但是忽略了加法作为算数运算符的优先级,其实结果会先算 y+x,故而与目标结果背道而驰

得出结论:宏函数不能加分号,为了避免保证运算中合理的优先级,应该在外面和里面加上括号。


C++表示:这宏函数是在预处理直接展开成了表达式,不像普通函数还要建立栈帧。但是也忒麻烦了点,稍有不慎,结果就不正确了。

于是,C++引入了关键字inline 就是替代C语言中的宏函数。

inline

inline既然要替代,首先它要延续宏函数的优点:调用函数时不用创建栈帧,直接展开,还要优于宏函数:方便书写—— inline 直接在函数定义的 返回类型前加上即可。

inline int Add(int x, int y)//现在写个函数+inline就方便很多了
{return x + y;
}
int main()
{int b = Add(1,2);return 0;
}
inline对于编译器⽽⾔只是⼀个建议,也就是说,你加了inline编译器也可以选择在调⽤的地⽅不展
开,不同编译器关于inline什么情况展开各不相同,因为C++标准没有规定这个。inline适⽤于频繁
调⽤的短⼩函数,对于递归函数,代码相对多⼀些的函数,加上inline也会被编译器忽略。
对于过长的函数作为内联函数,若也被频繁调用,此时已经不适合展开:比如下面这个场景:一个函数初次编译100条指令,编译完后成为一条指令。(在编译后的代码中,直接调用一个函数(尤其是在同一编译单元或模块内)通常涉及很小的开销,可能只是一条指令(比如一个跳转)。 )在函数在被复用时,就会执行被调用次的指令条数。

而如果编译器不阻拦这种展开,直接执行10000 * 100的指令,效率慢得可想而知。 

所以,inline适合短小、频繁调用的函数。

inline不建议声明和定义分离到两个⽂件,分离会导致链接错误。因为inline被展开,就没有函数地址,链接时会出现报错。

比如:

//F.h 声明
#pragma once
inline void f(int a);
//F.cpp 函数定义
#include "F.h"
#include <iostream>
using namespace std;
void f(int a)
{cout << a << endl;
}
//执行文件
#include "F.h"
int main()
{f(10);return 0;
}

如上述代码所示:我们把声明和定义放在两个文件

报错:  

内联函数编译器默认认为是不需要地址的,因为已经在调用地方展开了。在测试代码中,头文件展开,但是只有函数F的声明,找不到它的实现,导致调用地方展不开函数。

为什么找不到它的实现(展不开函数),因为在F.cpp中,虽然也包含了F.h,但是前面加了inline,默认是内联函数。这时候就不会把函数的实现地址放进符号表,导致测试代码中,无法链接到所调用函数的定义。

等到后面有更多的知识补充,我们会更好理解链接错误这一概念

总结: inline不建议声明和定义分离到两个⽂件,分离会导致链接错误。

相关文章:

C++_2_ inline内联函数 宏函数(2/3)

C推出了inline关键字&#xff0c;其目的是为了替代C语言中的宏函数。 我们先来回顾宏函数&#xff1a; 宏函数 现有个需求&#xff1a;要求你写一个Add(x,y)的宏函数。 正确的写法有一种&#xff0c;错误的写法倒是五花八门&#xff0c;我们先来“见不贤而自省也。” // …...

ROS执行多个节点报错(遥控运动及SLAM建图)

今天在实体机器人中同时执行多个ROS节点: roslaunch rei_robot_base oryxbot_base.launchroslaunch robot_joy robot_joy.launchroslaunch oryxbot_slam oryxbot_slam_local.launch结果全部报错退出了 现在换一种执行方式: roscoreroslaunch rei_robot_base oryxbot_base.la…...

Spring Boot项目中实现文件的上传、下载和预览功能

在Spring Boot项目中实现文件的上传、下载和预览功能&#xff0c;可以通过使用Spring MVC的MultipartFile接口来处理文件上传&#xff0c;并使用HttpServletResponse或Resource来实现文件下载和预览。下面是如何实现这些功能的完整示例。 1. 引入依赖 确保在pom.xml中引入了S…...

【JAVA入门】Day21 - 时间类

【JAVA入门】Day21 - 时间类 文章目录 【JAVA入门】Day21 - 时间类一、JDK7前的时间相关类1.1 Date1.2 SimpleDateFormat1.3 Calendar 二、JDK8新增的时间相关类2.1 Date 相关类2.1.1 ZoneId 时区2.1.2 Instant 时间戳2.1.3 ZoneDateTime 带时区的时间 2.2 DateTimeFormat 相关…...

SQL server数据库备份和还原

新手小白都懂的sql server数据库备份和还原 一、备份 1.打开sql server数据库找到 2.展开找到对应的数据库文件 鼠标右击—任务–备份 3.复制名称 4.复制完点击添加 5.点击添加完之后再次点击查找路径 6.分别两个路径 原路径和新路径 &#xff08;新路径是找到原路径新建了一…...

B站搜索建库架构优化实践

前言 搜索是B站的重要基础功能&#xff0c;需要对包括视频、评论、图文等海量的站内优质资源建立索引&#xff0c;处理来自用户每日数亿的检索请求。离线索引数据的正确、高效产出是搜索业务的基础。我们在这里分享搜索离线架构整体的改造实践&#xff1a;从周期长&#xff0c;…...

XSS反射实战

目录 1.XSS向量编码 2.xss靶场训练&#xff08;easy&#xff09; 2.1第一关 2.2第二关 方法一 方法二 2.3第三关 2.4第四关 2.5第五关 2.6第六关 2.7第七关 第一种方法&#xff1a; 第二种方法&#xff1a; 第三个方法&#xff1a; 2.8第八关 1.XSS向量编码 &…...

远程消息传递的艺术:NSDistantObject在Objective-C中的妙用

标题&#xff1a;远程消息传递的艺术&#xff1a;NSDistantObject在Objective-C中的妙用 引言 在Objective-C的丰富生态中&#xff0c;NSDistantObject扮演着至关重要的角色&#xff0c;特别是在处理分布式系统中的远程消息传递。它允许对象之间跨越不同地址空间进行通信&…...

指向派生类的基类指针、强转为 void* 再转为基类指针、此时调用虚函数会发生什么?

指向派生类的基类指针、强转为 void* 再转为基类指针、此时调用虚函数会发生什么&#xff1f; 1、无论指针类型怎么转&#xff0c;类对象内存没有发生任何变化&#xff0c;还是vfptr指向虚函数表&#xff0c;下面是成员变量&#xff0c;这在编译阶段就已经确定好了&#xff1b…...

操作系统(Linux实战)-进程创建、同步与锁、通信、调度算法-学习笔记

1. 进程的基础概念 1.1 进程是什么&#xff1f; 定义&#xff1a; 进程是操作系统管理的一个程序实例。它包含程序代码及其当前活动的状态。每个进程有自己的内存地址空间&#xff0c;拥有独立的栈、堆、全局变量等。操作系统通过进程来分配资源&#xff08;如 CPU 时间、内…...

react的setState中为什么不能用++?

背景&#xff1a; 在使用react的过程中产生了一些困惑&#xff0c;handleClick函数的功能是记录点击次数&#xff0c;handleClick函数被绑定到按钮中&#xff0c;每点击一次将通过this.state.counter将累计的点击次数显示在页面上 困惑&#xff1a; 为什么不能直接写prevStat…...

2.2算法的时间复杂度与空间复杂度——经典OJ

本博客的OJ标题均已插入超链接&#xff0c;点击可直接跳转~ 一、消失的数字 1、题目描述 数组nums包含从0到n的所有整数&#xff0c;但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在O(n)时间内完成吗&#xff1f; 2、题目分析 &#xff08;1&#xff09;numsS…...

【CentOS 】DHCP 更改为静态 IP 地址并且遇到无法联网

文章目录 引言解决方式标题1. **编辑网络配置文件**&#xff1a;标题2. **确保配置文件包含以下内容**&#xff1a;特别注意 标题3. **重启网络服务**&#xff1a;标题4. **检查配置是否生效**&#xff1a;标题5. **测试网络连接**&#xff1a;标题6. **检查路由表**&#xff1…...

Linux 操作系统 --- 信号

序言 在本篇内容中&#xff0c;将为大家介绍在操作系统中的一个重要的机制 — 信号。大家可能感到疑惑&#xff0c;好像我在使用 Linux 的过程中并没有接触过信号&#xff0c;这是啥呀&#xff1f;其实我们经常遇到过&#xff0c;当我们运行的进程当进程尝试访问非法内存地址时…...

黑马前端——days09_css

案例 1 页面框架文件 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equiv"X-UA-Compati…...

【Python爬虫】技术深度探索与实践

目录 引言 第一部分&#xff1a;Python爬虫基础 1.1 网络基础 1.2 Python爬虫基本流程 第二部分&#xff1a;进阶技术 2.1 动态网页抓取 2.2 异步编程与并发 2.3 反爬虫机制与应对 第三部分&#xff1a;实践案例 第四部分&#xff1a;法律与道德考量 第五部分&#x…...

智启万象|挖掘广告变现潜力,保障支付安全便捷

谷歌致力于为开发者提供 先进的广告变现与支付解决方案 一起回顾 2024 Google 开发者大会 了解如何利用谷歌最新工具和功能 提高变现收入&#xff0c;优化用户体验&#xff0c;保障交易安全 让变现更上一层楼 广告检查器是谷歌 AdMob 平台最新推出的高级测试工具&#xff0c;开…...

函数递归,匿名、内置行数,模块和包,开发规范

一、递归与二分法 一&#xff09;递归 1、递归调用的定义 递归调用&#xff1a;在调用一个函数的过程中&#xff0c;直接或间接地调用了函数本身 2、递归分为两类&#xff1a;直接与间接 #直接 def func():print(from func)func()func() # 间接 def foo():print(from foo)bar…...

Springboot3 整合swagger

一、pom.xml <dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-starter-webmvc-api</artifactId><version>2.1.0</version></dependency> 二、application.yml # SpringDoc配置 # springdoc:swa…...

查看同一网段内所有设备的ip

使用命令提示符&#xff08;CMD&#xff09;进行扫描 查看本机IP地址 首先通过 ipconfig /all 命令查看本机的IP地址&#xff0c;确定你的网段&#xff0c;例如 192.168.1.。 Ping网段内每个IP地址 接着使用循环命令&#xff1a; for /L %i IN (1,1,254) DO ping -w 1 -n …...

工业安全零事故的智能守护者:一体化AI智能安防平台

前言&#xff1a; 通过AI视觉技术&#xff0c;为船厂提供全面的安全监控解决方案&#xff0c;涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面&#xff0c;能够实现对应负责人反馈机制&#xff0c;并最终实现数据的统计报表。提升船厂…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)

CSI-2 协议详细解析 (一&#xff09; 1. CSI-2层定义&#xff08;CSI-2 Layer Definitions&#xff09; 分层结构 &#xff1a;CSI-2协议分为6层&#xff1a; 物理层&#xff08;PHY Layer&#xff09; &#xff1a; 定义电气特性、时钟机制和传输介质&#xff08;导线&#…...

YSYX学习记录(八)

C语言&#xff0c;练习0&#xff1a; 先创建一个文件夹&#xff0c;我用的是物理机&#xff1a; 安装build-essential 练习1&#xff1a; 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件&#xff0c;随机修改或删除一部分&#xff0c;之后…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)

可以使用Sqliteviz这个网站免费编写sql语句&#xff0c;它能够让用户直接在浏览器内练习SQL的语法&#xff0c;不需要安装任何软件。 链接如下&#xff1a; sqliteviz 注意&#xff1a; 在转写SQL语法时&#xff0c;关键字之间有一个特定的顺序&#xff0c;这个顺序会影响到…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面

代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

什么是Ansible Jinja2

理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具&#xff0c;可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板&#xff0c;允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板&#xff0c;并通…...