80 C++对象模型探索。数据语义学 - 数据成员布局-成员变量的地址规律,字节对齐问题,成员变量偏移值

news2024/9/27 2:50:28

一。观察成员变量地址规律

静态成员变量 不占用 类对象 的空间

1.普通成员变量的存储顺序,是按照在类中的定义顺序从上到下 来的

class Teacher4 {
public:
	int m_i;
	static int m_si;//这里是声明一个static,并不是定义,声明不会分配空间
	int m_j;
	static int m_sj;
	int m_k;
	static int m_sk;
};

int Teacher4::m_si = 100;//静态成员变量 不占用 类对象 的空间,实际上从上一节我们知道,静态成员变量是放在数据段或者BSS段的,也就是说,在编译阶段就已经确定了地址。


void main() {
	Teacher4 tea;
	cout<< sizeof(tea) << endl;//12

	//普通成员变量的存储顺序,是按照在类中的定义顺序从上到下 来的
	//如下的代码我们故意先给 m_k = 8,然后再m_j = 5;
	tea.m_i = 2;
	tea.m_k = 8;
	tea.m_j = 5;

	//堆上呢?
	Teacher4* ptea =  new Teacher4();
	printf("堆上分配空间 ptea->m_i 的地址 = %p \n", &ptea->m_i);
	printf("堆上分配空间 ptea->m_j 的地址 = %p \n", &ptea->m_j);
	printf("堆上分配空间 ptea->m_k 的地址 = %p \n", &ptea->m_k);
	
	//  堆上分配空间 ptea->m_i 的地址 = 00DF0958
	//	堆上分配空间 ptea->m_j 的地址 = 00DF095C
	//	堆上分配空间 ptea->m_k 的地址 = 00DF0960
	
	//规律1:比较晚出现的成员变量,地址比较高
	//规律2:类定义中 public,private,protected有多少了,都不会影响sizeof(Teacher4)
	

	cout << "duandian " << endl;
}

我们看到,普通成员变量 的 存储顺序,是按照在类中的定义顺序从上到下 来的

注意 vs2017中的查看某个变量的地址方法, 和查看mem的方法 

二。边界调整,字节对齐

//字节调整分析
//某些因素会导致成员变量之间排列不连续,这就是自己对齐,调整的目的是提高效率,其过程是编译器自动调整的
//如何调整:往成员之间填补一些字节,使类对象的sizeof,变成一个4的整数倍,有的时候变成8的整数倍
//关于字节对齐实际上再前面已经分析过了,参考:
CSDN

//不加#pragma pack(1) 运行结果是 20, 使用#pragma pack(1) 结果就变成了17
    //这种字节对齐有个问题,就是不同的编译器上,
    //字节对齐方式是不同的。例如在windows 的 vs2017 和linux上的g++就是不同的。
    //在实际开发中,就会有问题。例如网络程序,你怎么知道对方的用的是windows电脑还是linux,还是apple
    //因此,为了统一字节,引入一个概念,叫一字节对齐。也就是不对齐 
    //一字节对齐 使用方式是在class 文件的头部写 #pragma pack(1) 表示1字节对齐。
    //然后再class最后边 写上  #pragma pack() 表示结束。
    //也就是说,可以只对某一个类进行字节对齐声明

//字节调整分析
//某些因素会导致成员变量之间排列不连续,这就是自己对齐,
调整的目的是提高效率,其过程是编译器自动调整的
//如何调整:往成员之间填补一些字节,使类对象的sizeof,
变成一个4的整数倍,有的时候变成8的整数倍
//关于字节对齐实际上再前面已经分析过了,参考:
https://mp.csdn.net/mp_blog/creation/editor/135105140

#pragma pack(1)
class Teacher5 {
public:
	int m_i;
	static int m_si;
	int m_j;
	static int m_sj;
	int m_k;
	static int m_sk;
	char m_c;
	int m_n;
};
#pragma pack() //取消指定对齐方式。恢复默认的对齐方式。


void main() {
	cout << sizeof(Teacher5) << endl;//20, 使用#pragma pack(1) 结果就变成了17
	//这种字节对齐有个问题,就是不同的编译器上,
	//字节对齐方式是不同的。例如在windows 的 vs2017 和linux上的g++就是不同的。
	//在实际开发中,就会有问题。例如网络程序,你怎么知道对方的用的是windows电脑还是linux,还是apple
	//因此,为了统一字节,引入一个概念,叫一字节对齐。也就是不对齐 
	//一字节对齐 使用方式是在class 文件的头部写 #pragma pack(1) 表示1字节对齐。
	//然后再class最后边 写上  #pragma pack() 表示结束。
	//也就是说,可以只对某一个类进行字节对齐声明
}

三,成员变量偏移值的打印

成员变量的偏移值,就是这个成员变量的地址,离对象首地址偏移多少?

方式一:使用 c风格的%p, 显示 &Teacher6::m_i

printf("Teacher6::m_i = %p\n", &Teacher6::m_i);

方式二,使用宏定义

#define GET(A,m) (int) (&((A*)0)->m)

//解释一下这个宏。
//1,(A*)0 的意思是告诉编译器,将0X00000000这块地址用A *去解释。这里就是 用 Teacher6 * 去解释
//2. ((A*)0)就表示这个指针。
//3.由于 ->的优先级是高于 &,
//4.因此要先 计算 ((A*)0)->m,实际上就是找到指针A中的成员变量m。注意只是找到,并没有访问。如果是((A*)0)->m = 90;程序就挂了
//5.找到了 变量m在A中的值。然后再&,就是取地址,因为A* 是00000000,那么&(A*)->m就可以理解为偏移量

方式三,使用成员变量指针


    int Teacher6::*pmj = &Teacher6::m_j;
    printf("Teacher6::m_j的偏移值为%d\n",pmj); // 4

//还有一种写法,计算偏移值

#define GET(A,m) (int) (&((A*)0)->m)

//解释一下这个宏。
//1,(A*)0 的意思是告诉编译器,将0X00000000这块地址用A *去解释。这里就是 用 Teacher6 * 去解释
//2. ((A*)0)就表示这个指针。
//3.由于 ->的优先级是高于 &,
//4.因此要先 计算 ((A*)0)->m,实际上就是找到指针A中的成员变量m。注意只是找到,并没有访问。如果是((A*)0)->m = 90;程序就挂了
//5.找到了 变量m在A中的值。然后再&,就是取地址,因为A* 是00000000,那么&(A*)->m就可以理解为偏移量



class Teacher6 {
public:
	int m_i;
	static int m_si;
	int m_j;
	static int m_sj;
	int m_k;
	static int m_sk;
	char m_c;
	int m_n;
};

void main() {
	//打印成员变量 距 类的距离
	Teacher6 tea;
	printf("Teacher6::m_i = %p\n", &Teacher6::m_i);
	printf("Teacher6::m_j = %p\n", &Teacher6::m_j);
	printf("Teacher6::m_k = %p\n", &Teacher6::m_k);
	printf("Teacher6::m_c = %p\n", &Teacher6::m_c);
	printf("Teacher6::m_n = %p\n", &Teacher6::m_n);
	cout << "宏定义计算Teacher6::m_n = " << GET(Teacher6,m_n) << endl;

	//Teacher6::m_i = 00000000
	//	Teacher6::m_j = 00000004
	//	Teacher6::m_k = 00000008
	//	Teacher6::m_c = 0000000C
	//	Teacher6::m_n = 00000010
	//  宏定义计算Teacher6::m_n = 16

	// 这里有个额外的问题,使用cout打印的时候,发现 &Teacher6::m_i的值都是1,为啥呢?
	cout <<  (int Teacher6::*)(&Teacher6::m_i) << endl;
	cout << &Teacher6::m_j << endl; //1
	cout << &Teacher6::m_k << endl;//1
	cout << &Teacher6::m_c << endl;//1
	cout << &Teacher6::m_n << endl;//1

	//也可以使用成员变量指针
	int Teacher6::*pmj = &Teacher6::m_j;
	printf("Teacher6::m_j的偏移值为%d\n",pmj); // 4
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1414679.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

上位机图像处理和嵌入式模块部署(多ui文件使用)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 编写上位机程序的时候&#xff0c;qt wizard一般会帮我们创建一个ui文件。不过这个ui文件一般就是主窗口布局文件。当然&#xff0c;因为软件在执行…

北斗卫星为野外科考人员提供安全保障

北斗卫星为野外科考人员提供安全保障 自第二次青藏高原综合科学考察研究启动以来&#xff0c;青海不断提升科考服务保障能力&#xff0c;推动科考全程信息化&#xff0c;有效促进科考成果转化。 为保障科考人员的人身安全&#xff0c;青海省青藏科学考察服务中心开发了基于北…

ORB-SLAM中的RANSAC算法解析

RANSAC算法解析 RANSAC是一种在具有噪声的模型中去估计最优的一个算法&#xff0c;其核心思想是采用不断迭代的方法去选择一组全是内点的集合&#xff0c;并采用该集合进行模型估计的一种方法&#xff0c;可以提高模型估计的鲁棒性。 假设目前有 K K K组采集到的数据&#xff…

手把手教你搓一个最小系统板【画PCB-->布线 -->制版-->焊接】

文章目录 一、基础电路1. 晶振电路2. 稳压电路3. 复位/按键电路4. BOOT电路5. SWD接口6. 滤波电容7. LED电路8. 拓展引脚设计总览 二、布局布线三、制版四、焊接 在大学嵌入式相关专业&#xff0c;有许多同学是更偏向软件上的设计&#xff0c;并不懂硬件上的实现&#xff0c;而…

CMake构建Qt工程

在https://blog.csdn.net/fengbingchun/category_12172633.html 上有直接通过vs2022建的Console、Widgets、Quick三个工程&#xff0c;这里增加通过CMake构建。 build.sh内容如下&#xff1a; #! /bin/bashif [ $# ! 1 ]; thenecho "Error: requires one parameter: Rele…

(八)springboot实战——springboot3下的webflux项目全局异常处理

前言 在webflux响应式编程中&#xff0c;如何处理系统运行时异常是本节的主要内容。在传统的Servlet阻塞式web项目中主要通过HandlerExceptionResolver处理器来处理&#xff0c;而在webflux响应式web项目中&#xff0c;则是通过DispatchExceptionHandler异常处理器来处理异常。…

vue模拟聊天页面列表:滚动到底部,滚动到顶部触发加载更多

先看下效果&#xff1a; 代码&#xff1a; <template><div><div style"text-align: center"><button click"scrollTop">滚动到顶部</button><button click"scrollBottom">滚动到底部</button></d…

R12.2 EBS 修改 APPS 密码 详细步骤

目录 前言准备修改步骤1.关闭应用层2.FNDCPASS 修改密码3. 运行 autoconfig4.单独启动 webLogic 服务5.登录weblogic&#xff0c;更新apps密码6.启动应用层7.验证 结尾 前言 本文的目的是修改 apps 密码&#xff0c;主要参考官方文档 metalink 1674462.1&#xff0c;请注意本文…

go语言(十九)---- channel

channel的使用 //1. 发送value到channelchannel <- value //2. 接收并将其丢弃<- channel //3. 从channel中接收数据&#xff0c;并将其赋值给x x : <- channel 例子 package mainimport "fmt"func main() {//定义一个channelc : make(chan int)go func…

如何在Shopee平台上进行宠物类目的选品丨shopee宠物选品

在Shopee平台上进行宠物类目的选品是一个重要的任务&#xff0c;它直接关系到卖家的销售业绩和市场竞争力。为了成功选择适合的宠物用品&#xff0c;在选品过程中&#xff0c;卖家可以遵循以下策略&#xff1a; 先给大家推荐一款shopee知虾数据运营工具知虾免费体验地址&#…

【C语言/数据结构】排序(直接插入排序|希尔排序)

&#x1f308;个人主页&#xff1a;秦jh__https://blog.csdn.net/qinjh_?spm1010.2135.3001.5343&#x1f525; 系列专栏&#xff1a;《数据结构》https://blog.csdn.net/qinjh_/category_12536791.html?spm1001.2014.3001.5482 ​​​​ 目录 插入排序 直接插入排序&…

网站服务器中毒或是被入侵该怎么办?

随着互联网的普及和发展&#xff0c;网站服务器已经成为了企业和个人存储数据、展示信息的重要平台。然而&#xff0c;网络安全问题也日益突出&#xff0c;其中网站服务器中毒或被入侵的事件时有发生。一旦发生这种情况&#xff0c;不仅会导致网站无法正常运行&#xff0c;还可…

大数据期望最大化(EM)算法:从理论到实战全解析

文章目录 大数据期望最大化&#xff08;EM&#xff09;算法&#xff1a;从理论到实战全解析一、引言概率模型与隐变量极大似然估计&#xff08;MLE&#xff09;Jensen不等式 二、基础数学原理条件概率与联合概率似然函数Kullback-Leibler散度贝叶斯推断 三、EM算法的核心思想期…

Scratch:启蒙少儿编程的图形化魔法

在当今这个数字化时代&#xff0c;编程已经成为了一项重要的基础技能。就像学习阅读和写作一样&#xff0c;掌握编程能够打开通往未来世界的大门。对于孩子们来说&#xff0c;Scratch作为一种图形化编程语言&#xff0c;不仅简单有趣&#xff0c;而且非常适合作为编程学习的入门…

蓝桥杯——每日一练(简单题)

题目 问题描述   123321是一个非常特殊的数&#xff0c;它从左边读和从右边读是一样的。   输入一个正整数n&#xff0c; 编程求所有这样的五位和六位十进制数&#xff0c;满足各位数字之和等于n 。 输入格式   输入一行&#xff0c;包含一个正整数n。 输出格式   按从…

SpringBoot系列之JPA实现按年月日查询

SpringBoot系列之JPA实现按年月日查询 通过例子的方式介绍Springboot集成Spring Data JPA的方法&#xff0c;进行实验&#xff0c;要先创建一个Initializer工程&#xff0c;如图&#xff1a; 选择&#xff0c;需要的jdk版本&#xff0c;maven项目 选择需要的maven配置&#x…

最小二乘3D圆拟合(高斯牛顿法)

欢迎关注更多精彩 关注我&#xff0c;学习常用算法与数据结构&#xff0c;一题多解&#xff0c;降维打击。 本期话题&#xff1a;最小二乘3D圆拟合 相关背景资料 点击前往 3D圆拟合输入和输出要求 输入 8到50个点&#xff0c;全部采样自3D圆上。每个点3个坐标&#xff0c;坐…

pom文件首行报错问题处理

项目开发过程中&#xff0c;有时候在田间某个以来的时&#xff0c;会遇到pom文件首行报错&#xff0c;如下图所示 1、将鼠标移动到首行报错位置&#xff0c;点击红色❌&#xff0c;便会显示报错原因&#xff0c;这个项目遇到报错原因为“Missing artifact jdk.tools:jdk.tools:…

两个让你心跳加速的网站,赶紧收藏吧

1、方小童在线工具集 网址&#xff1a; 方小童 该网站是一款在线工具集合的网站&#xff0c;目前包含PDF文件在线转换、随机生成美女图片、精美壁纸等功能&#xff0c;喜欢的可以赶紧去试试&#xff01; 2、电子书搜索 网址&#xff1a;https://libstc.cc 很强大一个网站&a…

搭建nginx图片服务器

&#xff08;1&#xff09;将图片存储于/home/data/images目录&#xff1b; &#xff08;2&#xff09;配置nginx.conf user nginx; worker_processes 4;error_log /var/log/nginx/error.log notice; pid /var/run/nginx.pid;events {worker_connections 10000; }ht…