代码编织梦想

对于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_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	movl	%edi, -4(%rbp)
	movl	-4(%rbp), %edx
	movl	%edx, %eax
	addl	%eax, %eax
	addl	%edx, %eax
	movl	%eax, -4(%rbp)
	movl	-4(%rbp), %eax
	popq	%rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	foo, .-foo
	.globl	main
	.type	main, @function
main:
.LFB1:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	subq	$16, %rsp
	movl	$2, %edi
	call	foo
	movl	%eax, -4(%rbp)
	movl	$1, %edi
	call	foo
	addl	%eax, -4(%rbp)
	movl	-4(%rbp), %eax
	leave
	.cfi_def_cfa 7, 8
	ret
	.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_startproc
	leal	(%rdi,%rdi,2), %eax
	ret
	.cfi_endproc
.LFE0:
	.size	foo, .-foo
	.globl	main
	.type	main, @function
main:
.LFB1:
	.cfi_startproc
	movl	$9, %eax
	ret
	.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也不可滥用,这是因为原本只需要一份的函数被展开到整个工程中各个使用点上,虽然效率会有些许提升,但是指令数量可能会大幅增长,导致可执行程序体积过大。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_40960130/article/details/135300306

c语言关键字inline-爱代码爱编程

C语言关键字Inline Inline :提高了运行速度,但是会增加代码量(省去了调用函数的开销,但是包含的函数的代码量会增多) 1. inline 定义的类的内联函数,函数的代码被放入符号表中,在使用时直接进行替换,

c语言关键字之inline_dinguxiu的博客-爱代码爱编程_inline是c语言关键字吗

1. 内联函数 1.1. 何为内联函数 C语言中,如果一些函数被频繁的调用,不断的有函数入栈,即函数栈,会造成栈空间的大量消耗 为了解决这个问题,特别的引入 inline 修饰符,表示为内联函数 被定义为内联的函数,

c语言关键字浅析-inline_johan_joe_king的博客-爱代码爱编程

### C语言关键字浅析系列 ### ### ISO/ANSI C 关键字 ### inline关键字是C99标准新增的,是在某些方面比较实用的一个关键字 inline常出现在定义内联函数的地方,这也是它最重要的使命   inline的作用是: 定义内联函数。   1、何为内联函数? 内联函数的提出与C语言本身的一些特质有关,众所周知,C

C语言-inline关键字-爱代码爱编程

By: Ailson Jack Date: 2021.03.14 个人博客:http://www.only2fire.com/ 本文在我博客的地址是:http://www.only2fire.com/archives/131.html,排版更好,便于学习,也可以去我博客逛逛,兴许有你想要的内容呢。 1.基本概念 C语言中的inline关键字是C99标准

c语言inline有什么作用,C语言inline关键字-爱代码爱编程

一、inline关键字的概念 inline关键字是C99标准的型关键字,其作用是将函数展开,吧函数的代码复制到每一个调用处。这样调用函数的过程就可以直接执行函数代码,而不发生跳转、压栈等一般性函数操作。可以节省时间,也会提高程序的执行速度。 二、inline关键字实例 在编写程序过程中,对于短小而且需要频繁调用的函数,可以将其声明为inlin

C++ Inline关键字-爱代码爱编程

原创文章,转载请注明出处。 C++ Inline记录 前言1>inline 函数工作原理2>inline 函数作用2.1>消除函数调用的开销宏定义(define)和内联函数(inline)的区别1>内联函数是在编译时展开,而宏在编译预处理时展开;在编译的时候,内联函数直接被嵌入到目标代码中去,而宏只是一个简单的文本替换。

【c语言】inline 关键字-爱代码爱编程

在C语言中,inline关键字用于建议编译器对函数进行内联展开,而不是像普通函数一样调用。内联函数的目的是减少函数调用的开销,特别是对于简单的、频繁调用的函数。 内联函数的定义和使用 定义内联函数 要定义一个内联函

c语言基础知识-爱代码爱编程

目录 一、什么是内联函数 二、内联函数和宏区别 1、宏定义 2、内联函数 3、内联和宏对比 三、内联函数和普通函数 1、普通函数调用过程 2、内联函数调用过程 3、普通函数和内联函数对比 四、总结 一、什么是内联函数 内联关键字是inline,用于修饰函数,内联函数的实现需要用inline关键字修饰,内

逆向学习汇编篇:参数传递与返回地址的使用-爱代码爱编程

本节课在线学习视频(网盘地址,保存后即可免费观看): ​​https://pan.quark.cn/s/b5b046015da2​​ 在汇编语言中,函数调用和参数传递是编程的基础组成部分。了解如何在汇编中传递参数以及如何处理返回地址对于逆向工程师来说至关重要。本文将探讨x86架构下的参数传递机制和返回地址的处理,并通过代码案例来展示这些概念的具体应用。