技术标签: c# C++ c++ C/C++、嵌入式知识整理 c语言 C/C++知识点汇总
目录
原文 C++类的虚函数表和虚函数在内存中的位置_JMW1407的博客-程序员秘密
关系:虚函数表指针(保存在堆或栈)->虚函数表(常量区 .rodata)->虚函数(代码段 .text)
虚函数表指针是虚函数表所在位置的地址。虚函数表指针属于对象实例。因而通过new 出来的对象的虚函数表指针位于堆,声名对象的虚函数表指针位于栈。
总结:
1.虚函数表指针位置取决于对象在哪。如果是new的对象,则存在堆上,如果是直接声明,则存在栈上。
2.虚函数表位于只读数据段(.rodata),即:C++内存模型中的常量区;
3.虚函数代码则位于代码段(.text),也就是C++内存模型中的代码区
先创建一个有虚函数的类A
class A
{
public:
A(){};
~A(){};
virtual void vfun(){cout<<"vfun called!"<<endl;}
};
既然要知道虚函数表的位置,那么自然就需要找到虚函数表的地址。我们知道,对于类A这种简单的类,其对象内存布局的最开始四个字节就是一个虚函数表指针(32位编译器),而这个指针变量的值自然就是虚函数表的地址了,因此,第一步就是获取这个虚函数表指针来找到虚函数表的地址
A *a = new A();
long vbaddr=*(int *)a; //虚函数表地址
由于只有一个虚函数,所以虚函数表的前4个字节肯定就是vfun的函数地址,因此根据虚函数表的地址还可以得到虚函数vfun的地址:
long vfaddr= *(int *)vbaddr; //虚函数A::vfun的地址
然后还可以根据vfun的地址来调用这个函数:
((void(*)(void))vfaddr)(); //根据得到的地址来调用虚函数
如果通过vfaddr来调用函数是成功的,那么就说明前面虚函数表的地址都是正确的。
得出以下程序:
#include <iostream>
using namespace std;
class A
{
public:
A(){};
~A(){};
virtual void vfun(){cout<<"vfun called!"<<endl;}
};
int main()
{
A *a = new A();
long vbaddr=*(int *)a; //虚函数表地址
long vfaddr= *(int *)vbaddr; //虚函数vfun地址
cout<<"addr of vb : "<<vbaddr<<endl;
cout<<"addr of vfun : "<<vfaddr<<endl;
((void(*)(void))vfaddr)(); //根据虚函数地址调用虚函数
delete a;
return 0;
}
用g++进行编译生成可执行文件,然后运行:
从运行结果可以看到,虚函数表的地址是0x400be0(4197344),虚函数vfun的地址为0x400aea(4197098),并且根据虚函数vfun的地址成功调用了虚函数,打印了“vfun called”,这说明获取的0x400be0确实是虚函数表的地址。
接下来就看看0x400be0这个地址在可执行文件内存中的哪个段。
用objdump -s 可以解析ELF格式的可执行文件中的分段信息:
每个分段的内容用Contents of section .xxx来分隔,xxx表示下面的内容属于哪个段。在这些段的内容中,每一行的第一个16进制数表示的是相应的段中的一个地址,以400238 2f6c6962 3634…这一行为例,首地址为0x400238,那么从0x400238到下一行首地址0x400248之间的16个字节中存放的数据就是0x2f 0x6c 0x69 0x62…
回到虚函数表的地址上来,前面说了,虚函数表的地址为0x400be0,现在来看看这个地址是属于哪个段:
可以看到,0x400be0这个地址,刚好就在.rodata这个段中,这个段就是C++中的常量区,并且还可以发现,从这个地址开始取4个字节“ea0a4000”,由于是小端模式,因此取出来的4字节数为0x400aea,是不是很眼熟呢?没错,这个地址就是前面求得的虚函数vfun的地址。
同理,根据虚函数vfun的0x400aea地址,还可以找到虚函数vfun的位置:
可以看到,虚函数vfun位于.text代码段,也就是C++中的代码区。
综上所述: 虚函数表指针区别于创建的对象是new还是直接声明而放于堆或栈上。C++中虚函数表位于只读数据段(.rodata),也就是C++内存模型中的常量区;而虚函数则位于代码段(.text),也就是C++内存模型中的代码区。
参考
1、https://blog.twofei.com/496/
2、https://blog.csdn.net/Lily_zhangrongli/article/details/106650195
3、https://blog.csdn.net/qq_28114615/article/details/98041319
TableId(value = “id”, type = IdType.ASSIGN_UUID)时myabtispuls的注解,用于给主键id生成一个UUID。这次的BUG,存粹是因为自己对框架理解的太肤浅造成。背景:前端传来的DTO参数,与数据库落表字段并不完全一致。因此自己实现了一个Dto,在保存数据落库时,报错。异常信息:大致内容就是id不能为空,我落表时候传的时空值。
自动注入容器的更多使用主要用于依赖注入,和5.0自动注入的方式有所区别,类的绑定操作不再使用Request 对象而是直接注册到容器中,并且支持模型事件和数据库事件的依赖注入,依赖注入会首先检查容器中是否注册过该对象实例,如果有的话就会自动注入...
在x86_64下和i386下是类似的,本文主要关注vm.legacy_va_layout以及kernel.randomize_va_space参数影响下的进程空间内存宏观布局,以及vDSO和多线程下的堆和栈分布。情形一:vm_legacy_va_layout=1kernel.randomize_va_space=0此种情况下采用传统内存布局方式,不开启随机化,程序的内存布局可以看出: 代码段:0x...
BGT24LTR22是英飞凌推出的一款雷达射频芯片,用它可以产生24Ghz的雷达信号。这是BGT24LTR22的评估版,本篇文章旨在使用XMS2Go与BGT24LTR22芯片进行SPI通信,以达到控制射频板的目的。首先使用Dave软件进行编程#define TICKS_PER_SECOND 1000#define TICKS_WAIT 1000uint8_t i=0;const uint8_t data[9] = {0x01,0x00,0x63,0x03,0x03,0xFD,0x0
计算机是如何工作的机器语言:机器语言直接用二进制代码指令表达的计算机语言,指令是用0和1组成的一串代码,可以被计算机直接理解,如上图的C706 0000 0002(以16进制书写,但在计算机中是二进制)汇编语言:汇编语言是面向机器的程序设计语言,使用助记符(Memoni)代替操作码,用地址符号(Symbol)或标号(Label)代替地址码。如上图的MOV X,2高级语言:高级语言是高度封...
文章目录1. 什么是垃圾1.1 大厂面试题1.2 什么是垃圾( Garbage) 呢?1.3 垃圾收集2. 为什么需要GC3. 早期垃圾回收4. Java垃圾回收机制1. 什么是垃圾Java = (C++)–1.1 大厂面试题蚂蚁金服:你知道哪几种垃圾回收器,各自的优缺点,重点讲一下 cms和g1一面: JVM GC算法有哪些,目前的JDK版本采用什么回收算法一面: ( G1回收器讲下回收过程GC是什么?为什么要有GC?一面: GC的两种判定方法? CMS收集器与G1收集器的特点。百
在很多情况下安装php是,如果通过yum安装,会导致安装的php版本比较低,如果在开发的时候用的是高版本的php,这个时候我们在服务器上安装php必须使用源码编译安装,如果在编译的时候报错了,可能需要很长的时间排错,然后重新编译安装,这样花费的时间比较长。使用yum安装指定版本的php1、下载对应的仓库## centos7 版本yum install -y https://mirrors.tuna.tsinghua.edu.cn/remi/enterprise/remi-release-7.rpm
react-native 开发App的时候难免会遇到状态,栏的,背景颜色和字体颜色与App内容页面,色调适配,间言之就是将状态栏颜色与App颜色一致,使用户界面更加整体。1.android设备系统元素导航栏:就是设备顶部的网络、时间、电量等信息栏ActionBar: 返回按钮以及系统默认的header区域,RN开发中一般不会用到,RN中在navigation中进行定制导航栏: 设备下方的物理返回、...
* 以下内容是我在准备java面试的时候觉得有用,面试官很可能会问的一些问题* 内容(除了代码)详情来自网络(学习的时候遇到不会的百度的 (*^__^*) )* 如果大家发现有什么地方不对,请告诉我。谢啦!!☆⌒(*^-゜)v1:java的基础类型Java语言提供了八种基本语言booleanchar byte 8位...
最小生成树之prim算法 最小生成树的概念在上一篇文章中已经叙述了,在这里主要再叙述一种解决最小生成树的算法--prim算法。 他其实和kruskal算法是互补的,一个从边出发,另一个从点出发寻找最小的总权值。prim算法是从点入手,一开始随机选一个点,找出该点连接的其他所有点中最短的路径,然后把这条边的另一个点加入集合。当集合中的点大于等于2的时候,我们每次都要找出这个集合中与其他不
来源商业新知网,原标题:学了 Python 能用来做什么?说起编程语言,Python 也许不是使用最广的,但一定是现在被谈论最多的。随着近年大数据、人工智能的兴起,Python 越来越多的出现在人们的视野中。那么人们在谈论 Python 的时候究竟在谈论什么?Python 的实际应用场景有哪些?这里给大家简单做一个介绍:Web 应用开发在因大数据、人工智能为人所熟知之...
题目31:山峰的个数描述:十一假期,小P出去爬山,爬山的过程中每隔10米他都会记录当前点的海拔高度(以一个浮点数表示),这些值序列保存在一个由浮点数组成的列表h中。回到家中,小P想研究一下自己经过了几个山峰,请你帮他计算一下,输出结果。例如:h=[0.9,1.2,1.22,1.1,1.6,0.99], 将这些高度顺序连线,会发现有两个山峰,故输出一个2(序列两端不算山峰)答案:count = 0f...