浅谈C语言inline关键字
对于C++开发者来说,inline是个再熟悉不过的关键字,因为默认的成员函数都是inline,也是常规高校教材中宣扬C++的“优势”之一。
但是C语言其实也是支持inline关键字的,而且是很早期的gcc就支持了该关键字。在Linux0.12版本内核代码中也用到了该关键字。
今天码哥浅谈一下这个关键字的作用和使用。
inline的作用浅显一点说,就是将声明了该关键字的函数不以call指令调用的方式来调用,而是直接将其展开在调用函数中。似乎感觉有点像宏展开的样子?
实际不然,我们以一个C语言示例来进行说明:
inline int foo(int a)
{a *= 3;return a;
}
int main(void)
{int a = foo(2);a += foo(1);return a;
}
例子很简单,foo函数被声明了inline,作用是将输入参数扩大三倍返回。
下面我们来看看这个例子的汇编是如何的。在此之前,需要重点提示:
inline关键字只有在开启了编译优化后才会启用,且如果函数定义时不声明为inline,那么inline只发生在有inline声明之后的调用点。
无编译优化汇编
$ gcc -S a.c
我们并未开启任何编译优化,其汇编如下:
.file "c.c".text.globl foo.type foo, @function
foo:
.LFB0:.cfi_startprocpushq %rbp.cfi_def_cfa_offset 16.cfi_offset 6, -16movq %rsp, %rbp.cfi_def_cfa_register 6movl %edi, -4(%rbp)movl -4(%rbp), %edxmovl %edx, %eaxaddl %eax, %eaxaddl %edx, %eaxmovl %eax, -4(%rbp)movl -4(%rbp), %eaxpopq %rbp.cfi_def_cfa 7, 8ret.cfi_endproc
.LFE0:.size foo, .-foo.globl main.type main, @function
main:
.LFB1:.cfi_startprocpushq %rbp.cfi_def_cfa_offset 16.cfi_offset 6, -16movq %rsp, %rbp.cfi_def_cfa_register 6subq $16, %rspmovl $2, %edicall foomovl %eax, -4(%rbp)movl $1, %edicall fooaddl %eax, -4(%rbp)movl -4(%rbp), %eaxleave.cfi_def_cfa 7, 8ret.cfi_endproc
.LFE1:.size main, .-main.ident "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-39)".section .note.GNU-stack,"",@progbits
可以看到在main中存在两个call指令调用foo函数,我们的inline关键字作用并未生效。
编译优化汇编
$ gcc -S a.c -O
我们仅启用O1优化,那么看下汇编成了什么样子呢?
.file "c.c".text.globl foo.type foo, @function
foo:
.LFB0:.cfi_startprocleal (%rdi,%rdi,2), %eaxret.cfi_endproc
.LFE0:.size foo, .-foo.globl main.type main, @function
main:
.LFB1:.cfi_startprocmovl $9, %eaxret.cfi_endproc
.LFE1:.size main, .-main.ident "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-39)".section .note.GNU-stack,"",@progbits
这里,码哥没有做任何删减。
读者可能会发现,main中返回值直接给了一个立即数9,而不是jmp到foo或者使用其相关指令计算的。这说明了什么呢?
这说明了,inline并不简简单单的类似宏扩展,而是编译器在编译时将foo代码展开进main中,并且在优化剪枝等优化步骤中对展开后的整体内容做优化,进而发现foo的输入与输出以及foo的两次调用结果是一个可推算的常数值。
因此,inline的作用不仅仅是避免了call指令的使用以及其关联的压栈弹栈等操作,更是可以让编译器对整体性能做出非常多改进优化,大幅提升性能。
但是,inline也不可滥用,这是因为原本只需要一份的函数被展开到整个工程中各个使用点上,虽然效率会有些许提升,但是指令数量可能会大幅增长,导致可执行程序体积过大。
相关文章:
浅谈C语言inline关键字
对于C开发者来说,inline是个再熟悉不过的关键字,因为默认的成员函数都是inline,也是常规高校教材中宣扬C的“优势”之一。 但是C语言其实也是支持inline关键字的,而且是很早期的gcc就支持了该关键字。在Linux0.12版本内核代码中也…...
Flink1.17实战教程(第六篇:容错机制)
系列文章目录 Flink1.17实战教程(第一篇:概念、部署、架构) Flink1.17实战教程(第二篇:DataStream API) Flink1.17实战教程(第三篇:时间和窗口) Flink1.17实战教程&…...
OpenCV实战 -- 维生素药片的检测记数
文章目录 检测记数原图经过操作开始进行消除粘连性--形态学变换总结实现方法1. 读取图片:2. 形态学处理:3. 二值化:4. 提取轮廓:5. 轮廓筛选和计数: 分水岭算法:逐行解释在基于距离变换的分水岭算法中&…...
【AI】注意力机制与深度学习模型
目录 一、注意力机制 二、了解发展历程 2.1 早期萌芽: 2.2 真正意义的注意力机制: 2.3 2015 年及以后: 2.4 自注意力与 Transformer: 2.5 BERT 与预训练模型: 三、基本框架 1. 打分函数(Score Fun…...
HTML5和JS实现新年礼花效果
HTML5和JS实现新年礼花效果 2023兔年再见,2024龙年来临了! 祝愿读者朋友们在2024年里,身体健康,心灵愉悦,梦想成真。 下面是用HTML5和JS实现新年礼花效果: 源码如下: <!DOCTYPE html>…...
【owt-server】一些构建项目梳理
【owt-server】清理日志:owt、srs、ffmpeg 【owt】p2p client mfc 工程梳理【m98】webrtc vs2017构建带符号的debug库【OWT】梳理构建的webrtc和owt mfc工程 m79的mfc客户端及owt-client...
Linux shell编程学习笔记38:history命令
目录 0 前言 1 history命令的功能、格式和退出状态1.1 history命令的功能1.2 history命令的格式1.3退出状态2 命令应用实例2.1 history:显示命令历史列表2.2 history -a:将当前会话的命令行历史追加到历史文件~/.bash_history中2.3 history -c…...
elasticsearch安装教程(超详细)
1.1 创建网络(单点部署) 因为我们还需要部署 kibana 容器,因此需要让 es 和 kibana 容器互联,所有先创建一个网络: docker network create es-net 1.2.加载镜像 采用的版本为 7.12.1 的 elasticsearch;…...
arkts中@Watch监听的使用
概述 Watch用于监听状态变量的变化,当状态变量变化时,Watch的回调方法将被调用。Watch在ArkUI框架内部判断数值有无更新使用的是严格相等(),遵循严格相等规范。当在严格相等为false的情况下,就会触发Watch的…...
【Jmeter】Jmeter基础9-BeanShell介绍
3、BeanShell BeanShell是一种完全符合Java语法规范的脚本语言,并且又拥有自己的一些语法和方法。 3.1、Jmeter中使用的BeanShell 在Jmeter中,除了配置元件,其他类型的元件中都有BeanShell。BeanShell 是一种完全符合Java语法规范的脚本语言,并且又拥…...
详解数组的轮转
𝙉𝙞𝙘𝙚!!👏🏻‧✧̣̥̇‧✦👏🏻‧✧̣̥̇‧✦ 👏🏻‧✧̣̥̇:Solitary-walk ⸝⋆ ━━━┓ - 个性标签 - :来于“云”的“羽球人”。…...
html 表格 笔记
<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>第二个页面</title><meta name"language" content"cn"> </head> <body><h2 sytle"width:500px;…...
计算机网络【HTTP 面试题】
HTTP的请求报文结构和响应报文结构 HTTP请求报文主要由请求行、请求头、空行、请求正文(Get请求没有请求正文)4部分组成。 1、请求行 由三部分组成,分别为:请求方法、URL以及协议版本,之间由空格分隔;请…...
linux基于用户身份对资源访问进行控制的解析及过程
linux中用户分为三类 1.超级用户(root) 拥有至高无上的权限 2.普通用户 人为创建、权限小,权限受到控制 3.程序用户 运行程序的用户,不是给人使用的,给程序使用的,一般不给登录! 组账…...
手动创建idea SpringBoot 项目
步骤一: 步骤二: 选择Spring initializer -> Project SDK 选择自己的JDK版本 ->Next 步骤三: Maven POM ->Next 步骤四: 根据JDK版本选择Spring Boot版本 11版本及以上JDK建议选用3.2版本,JDK为11版本…...
【Go语言入门:Go语言的数据结构】
文章目录 3.Go语言的数据结构:3.1. 指针3.2. struct(结构体)3.3. Map(映射,哈希) 3.Go语言的数据结构: 简介: 在Go语言中,数据结构体可以分为四种类型:基础类型、聚合类型、引用类型…...
QT designer的ui文件转py文件之后,实现pycharm中运行以方便修改逻辑,即添加实时模板框架
为PyCharm中的实时模板,你需要遵循以下步骤: 打开PyCharm的设置: 选择 File > Settings(在macOS上是 PyCharm > Preferences)。 导航到实时模板: 在设置中找到 Editor > Live Templates。 添加新的模板组 (可选): 为了…...
什么是负载均衡?
负载均衡是指在计算机网络领域中,将客户端请求分配到多台服务器上以实现带宽资源共享、优化资源利用率和提高系统性能的技术。负载均衡可以帮助小云有效解决单个服务器容量不足或性能瓶颈的问题,小云通过平衡流量负载,使得多台服务器能够共同…...
Python和Java的优缺点
Python的优点: 简单易学:Python的语法简洁清晰,易于学习和理解。丰富的库和框架:Python拥有庞大的标准库和活跃的开源社区,可以快速使用各种功能强大的库和框架,比如NumPy、Pandas、Django等。可读性强&am…...
AES - 在tiny-AES-c基础上封装了2个应用函数(加密/解密)
文章目录 AES - 在tiny-AES-c基础上封装了2个应用函数(加密/解密)概述增加2个封装函数的AES库aes.haes.c在官方测试程序上改的测试程序(用来测试这2个封装函数)END AES - 在tiny-AES-c基础上封装了2个应用函数(加密/解密) 概述 在github山有个星数很高的AES的C库 tiny-AES-c …...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...
MySQL中【正则表达式】用法
MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现(两者等价),用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例: 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...
作为测试我们应该关注redis哪些方面
1、功能测试 数据结构操作:验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化:测试aof和aof持久化机制,确保数据在开启后正确恢复。 事务:检查事务的原子性和回滚机制。 发布订阅:确保消息正确传递。 2、性…...
