首页 > 编程语言 >内联函数、引用、汇编

内联函数、引用、汇编

时间:2024-05-04 22:57:19浏览次数:25  
标签:汇编 00 函数 int eax 引用 内联 指针

内联函数

内联函数是一种特殊的 C++ 函数,编译器会将它的代码直接插入到调用它的位置,而不是像普通函数那样进行函数调用。这可以减少函数调用的开销,从而提高性能。

#include <iostream>
using namespace std;

int func(int v1, int v2) {
	return v1 + v2;

}

inline int func1(int v1, int v2) {
	return v1 + v2;
}

int main() {
	func(1, 2);
	func1(3, 4);
	return 0;
}

内联函数的优点

  • 提高性能:内联函数可以减少函数调用的开销,从而提高性能。
  • 减少代码大小:内联函数可以减少代码大小,因为编译器不会生成额外的函数调用指令。
  • 提高可读性:内联函数可以提高可读性,因为函数代码直接出现在调用它的位置。

使用场景

  1. 函数体积小
  2. 函数需要经常使用

引用

引用是 C++ 中一种强大的机制,它允许你以一种高效且类型安全的方式间接访问变量。引用与指针类似,但它们有以下几个关键区别:

  • 引用必须初始化:引用必须在声明时或之后立即初始化。
  • 引用不能重新绑定:一旦引用被初始化,它就不能再指向其他变量。
  • 引用与它所引用的变量共享存储空间:对引用的修改也会修改它所引用的变量。
  • 引用比指针更安全,

引用是一种“弱化的指针”,相当于给变量起别名。
举例说明引用的使用

#include <iostream>
using namespace std;

//指针
void swap_point(int* a, int* b) {
	int tmp = *a;
	*a = *b;
	*b = tmp;

}

//引用,相当与给变量取别名!
void swap_ref(int& a, int& b) {
	int tmp = a;
	a = b;
	b = tmp;

}

int main() {
	int s1 = 1, s2 = 2;
	int s3 = 3, s4 = 4;
	swap_point(&s1, &s2);
	cout << "s1 = " << s1 << ",s2 = " << s2 << endl;
	swap_ref(s3, s4);
	cout << "s3 = " << s3 << ",s4 = " << s4 << endl;
	getchar();
	return 0;
}

汇编分析
main函数
image.png
指针传值
image.png
引用传值
image.png
从以上可以看出,引用和指针本质一样,只是前者加了一些限制与简化,例如与const结合可以达到保护内存空间的效果,可以方便的直接操作某些变量的内存,而不需要通过取地址给指针、指针解引用等操作。
所有栈中的数据要进行计算,必须放到CPU的寄存器中,同样,函数的返回值也是存放在寄存器中的。
32位下指针变量占4字节,64位下指针变量占8字节。为了进一步证明它们本质一样,下面进行大小验证。
image.png
image.png
为什么要把引用变量放到结构体里面计算大小?
如果这样写,绝对是错误的。
image.png
前面说过,ref可以看作是变量的别名,那么输出语句可以这样理解,把a的大小,一个int输出了,明显得不到引用变量的大小。
image.png

为了进一步说明引用的本质就是指针,再看一个例子

int a = 10;
int& ref = a;
ref = 20;
----
C7 45 F4 0A 00 00 00 mov         dword ptr [a],0Ah  	;int a = 10;
8D 45 F4             lea         eax,[a]  				;int& ref = a;
89 45 E8             mov         dword ptr [ref],eax
8B 45 E8             mov         eax,dword ptr [ref]  	;ref = 20;
C7 00 14 00 00 00    mov         dword ptr [eax],14h  	
--------------------------------------------------
int b = 10;
int* p = &b;
*p = 20;
---
C7 45 DC 0A 00 00 00 mov         dword ptr [b],0Ah  	;int b = 10;
8D 45 DC             lea         eax,[b]  				;int* p = &b;
89 45 D0             mov         dword ptr [p],eax  
8B 45 D0             mov         eax,dword ptr [p]  	;*p = 20;
C7 00 14 00 00 00    mov         dword ptr [eax],14h 	

因为CPU架构的原因,每次需要操作内存空间时,需要提前将内存地址放到寄存器中。

汇编

两种格式

Intel 格式AT&T 格式是两种不同的汇编语言语法,用于 x86 架构的处理器。
Intel 格式由英特尔公司开发,是 x86 汇编语言最常见的语法。它使用以下约定:

  • 指令助记符写在操作数之前。
  • 寄存器使用单字母缩写(例如,eaxebx)。
  • 内存地址使用方括号(例如,[eax])。

AT&T 格式由贝尔实验室开发,主要用于 Unix 和类 Unix 系统。它使用以下约定:

  • 指令助记符写在操作数之后。
  • 寄存器使用百分号符号(例如,%eax%ebx)。
  • 内存地址使用圆括号(例如,(%eax))。

以下是用 Intel 格式和 AT&T 格式编写的相同汇编代码:
Intel 格式:

mov eax, 10
add eax, 5

AT&T 格式:

movl $10, %eax
addl $5, %eax

QuickStart

  1. CPU做计算时,必须先将值读入寄存器,然后再从寄存器中读取,不能直接操作内存
  2. RAX、RBX、RCX、RDX 是 64位下的通用寄存器,大小与指针大小一样,64位下占8字节
  3. []里存放的都是地址
  4. word 占2 字节, dword 占4 字节, qword 占8 字节
  5. 函数调用:call 函数地址 ——> jmp 真实函数地址 。

这是因为在汇编函数调用中,call 指令实际上不会跳转到函数的真实地址。相反,它执行以下操作:1. 将函数的返回地址压入堆栈。2. 跳转到函数的真实地址。
所以我们在汇编中调试call,执行的第一步实际上是push eip压栈操作,继续单步走到jmp,再走一步就到了函数真实地址。

  1. mov dword ptr [ebp - 8] , 3 (操作数、操作内存单位、变量指针标识符、地址、值)
  2. xor异或, xor eax,eax 多用于寄存器清零
  3. inc op 相当于 op++
  4. 函数调用call之前的push都是在传参

标签:汇编,00,函数,int,eax,引用,内联,指针
From: https://www.cnblogs.com/Rainy-Day/p/18172904

相关文章

  • C语言转写成MIPS指令集汇编以及MIPS指令集汇编中函数调用时栈的变化
    一、问候语欢迎你来到我的博客!二、C语言代码分析  这段C语言代码共有3个函数组成。set_array函数传入1个int类型的变量num,并创建了1个int类型临时变量i和1个临时int类型数组array,里面含有10个单位,此函数主要目的是调用compare函数,并将num和i传入该函数中,得到其函数返回值......
  • 值类型和引用类型的区别
    值类型---简单类型基本类型 比如数字,字符串布尔等 引用类型 -复杂类型对象类型比如对象函数委托等 区别:1.内存层面:值类型内存的分配和释放有编辑器管理,引用类型内存的分配和释放由垃圾回收期(GC)管理2.存储位层面:存储位置:值类型存储栈内存,只有数据;引......
  • Spark中的闭包引用和广播变量
    闭包引用概念所有编程语言都有闭包的概念,闭包就是在一个函数中引用了函数外的变量。Spark中,普通的变量是在Driver程序中创建的,RDD的计算是在分布式集群中的task程序上进行的。因此,当分布式算子的函数引用了外部的变量时,Driver会把该变量序列化后通过网络发送给每一个task(只......
  • 8086 汇编学习 Part 6
    用MUL指令做乘法格式MUL寄存器MUL寄存单元8位乘法16位乘法被乘数(默认)ALAX乘数8位寄存器或内存单元16位寄存器或内存字单元结果AXDX(高位)和AX(低位)模块化程序设计调用子程序:CALL指令返回:RET指令实质流程转移指令,它们都修改......
  • M3位带地址映射和汇编对比
    01.位带概述位带操作简单的说,就是把每个比特膨胀为一个32位的字,当访问这些字的时候就达到了访问比特的目的,比如说GPIO的ODR寄存器有32个位,那么可以映射到32个地址上,我们去访问这32个地址就达到访问32个比特的目的。这样我们往某个地址写1就达到往对应比特位写1......
  • SpringBoot 循环引用解决办法
    Spring原生是允许并解决了单层循环引用的,但从SpringBoot2.6.0开始,默认禁止Bean之间的循环引用,如果存在循环引用就会启动失败报错。此时要解决循环引用问题有两个办法:设置Spring允许循环引用(推荐)。spring:main:allow-circular-references:true在循环引用......
  • C++指针与引用(Pointers OR References)
    一、PointersPointer是指针,可以用来指向任何一个objects,包括一般变量:1inti=3;2int*pi=&i;3cout<<pi<<endl;//0x0064FDF04cout<<*pi<<endl;//3此时pi本身内含i的地址,要取出pi所指向的object,可以使用*运算符(dereferenceoperator).Pointer......
  • 8086 汇编学习 Part 5
    流程转移背景一般情况下指令是顺序地逐条执行的,而在实际中,常需要改变程序的执行流程。转移指令可以控制CPU执行内存中某处代码的指令。可以修改IP,或同时修改CS和IP的指令。分类按转移行为分类段内转移:只修改IP(例如JMPAX)段间转移:同时修改CS和IP(例......
  • 8086 汇编学习 Part 4
    寻址方式形式名称特点意义示例[idata]直接寻址用一个常量/立即数来表示地址用于直接定位一个内存单元MOVAX,[200][BX]寄存器间接寻址用一个变量来表示内存地址用于间接定位一个内存单元MOVAX,[BX][BX+idata]寄存器相对寻址用一个变量和常量......
  • httprunner 4.x学习 - 12 测试用例引用另一个测试用例
    前言把登录用例变 export导出变量,变成全局变量,这样其它用例可以引用登录用例config:name:登录variables:username:"admin1"password:"123456"teststeps:-name:postrequest:method:POSTurl:${ENV(base_url)}/loginjson:......