首页 > 编程语言 >C++结构体对齐详解

C++结构体对齐详解

时间:2023-05-30 12:11:17浏览次数:34  
标签:字节数 offset C++ a3 详解 长度 对齐 a2

  • 内存对齐是一种提高内存访问速度的策略,CPU在访问未对齐的内存可能需要经过两次的内存访问,而经过内存对齐一次就可以了
cout<<"char:"<<sizeof(char)<<endl;
cout<<"int:"<<sizeof(int)<<endl;
cout<<"short:"<<sizeof(short)<<endl;
cout<<"float:"<<sizeof(float)<<endl;
cout<<"double:"<<sizeof(double)<<endl;

结构体对齐原则

  1. 数据对齐原则:结构的数据成员每个数据成员存储的起始位置要从该成员大小的整数倍开始,第一个成员都是从0开始(因为0是任何整数的整数倍)
  2. 结构体作为成员:如果有一个结构里面有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍开始存储
  3. 结构体的总大小,必须是内部最大成员的整数倍
struct A1{
    char a1;
    int a2;
    char a3;
};

struct A2{
    char a1;
    char a2;
    int a3;
};

struct A3{
    char a1;
    int a2;
    double a3;
    char a4;
};

struct A4{
    char a1;
    struct A3 a2;
    int a3;
    double a4;
};
int main(){
    cout<<"A1:"<<sizeof(A1)<<endl;
    cout<<"A2:"<<sizeof(A2)<<endl;
    cout<<"A3:"<<sizeof(A3)<<endl;
    cout<<"A4:"<<sizeof(A4)<<endl;
}

上面代码的输出结果未

A1:12
A2:8
A3:24
A4:48

A1

  • a1在offset为0的地方(长度为1,范围为0-0)
  • a2在offset为4的地方(长度为4,范围为4-7 )
  • a3在offset为8的地方(长度为1,范围为8-8)
  • 此时大小为9,但是使用规则3,结构体大小应该为其内部最大成员的整数倍,也就是4的整数倍,所以此时A1的大小为12,则此时a3后面三个字节被填充补齐,所以此时A1的范围是0-11
    image

A2

  • a1在offset为0的地方(长度为1,范围是0-0)
  • a2在offset为1的地方(长度为1,范围是1-1)
  • a3在offset为4的地方(长度为4,范围是4-7)
  • 此时A2的大小为8
    image

A3

  • a1在offset为0的地方(长度为1,范围是0-0)
  • a2在offset为4的地方(长度为4,范围是4-7)
  • a3在offset为8的地方(长度为8,范围是8-15)
  • a4在offset为16的地方(长度为1,范围是16-16)
  • 此时结构体大小为17,根据规则3,此时结构体大小应该为8的整数倍,也就是24,所以A3的大小为24
    image

A4

  • a1在offset为0的地方(长度为1,范围是0-0)
  • 根据规则2,因为A3的成员最大为double8个字节,所以a2的offset为8(长度为24,范围是8-31)
  • a3在offset为32的地方(长度为4,范围是32-35)
  • a4在offset为40(长度为8,范围是40-47)
  • 所以结构体A4的大小为48
    image

上面解释了四个结构体的成员分布,并且将其内存分布使用图片的形式进行一个展现,我们从A1 A2可以知道成员变量的不同定义顺序会导致其结构体大小的不同

#pragma pack

  • #pragma pack(show) 会在编译阶段给出一个警告,说明当前对齐字节数,默认为8

  • #pragma pack() 将对齐字节数恢复成默认的对齐字节数

  • #pragma pack(n) n只能是1 2 4 8 16中的任意值,表示设置当前对齐字节数

  • #pragma pack(push) 将当前对齐字节数压入栈顶,并设这这个值为新的对齐字节数,也就是当前对齐字节数并没有改变

  • #pragma pack(push,n) 将当前对齐字节数压入栈顶,并设置n为新的对齐字节数

  • #pragma pack(pop) 会弹出栈顶对齐字节数,并设置为新的内存对齐字节数

  • #pragma pack(pop,n)弹出栈顶并直接丢弃,设置n为其新的内存对齐字节数

    • 在之前上面四个结构体前面加上#pragma pack(1),则输出变为了
A1:6
A2:6
A3:14
A4:27

这是因为将默认对齐字数改为1之后,在使用规则1 2 3进行计算的时候,都让1和之前大小取最小值,因为之前默认为8,所以可以获得之前的结果

A1

  • a1在offset为0的地方(长度为1,范围0-0)
  • a2在offset为1的地方(长度为4,范围为1-4),这是因为int的大小为4,之前默认对齐字节数为8,所以取4 8的最小值为4,将其放在4的整数倍上,而此时取值为4 1中的最小值为1,所以将其放在1的整数倍上
  • a3在offset为5的地方(长度为1,范围是5-5)
  • 之前默认对齐字数为8的时候,取得是数据成员变量最大值4和默认对齐字数8得最小值4,为结构体整体对齐得整数倍,而此时变为了4和1得最小值1,所以此时结构体应该是1的整数倍,所以结构体大小为6

其他三个结构体也是这么进行分析

标签:字节数,offset,C++,a3,详解,长度,对齐,a2
From: https://www.cnblogs.com/sunjianzhao/p/17442604.html

相关文章

  • c++11: all_of 、 any_of 和 none_of
    有效的字母异位词classSolution{public:boolisAnagram(strings,stringt){if(s.size()!=t.size())returnfalse;intans[26]={0};for(auto&ch:s){++ans[ch-'a'];}for(auto&......
  • 《asyncio 系列》3. 详解 Socket(阻塞、非阻塞),以及和 asyncio 的搭配
    楔子在前面两篇文章中,我们介绍了协程、任务和事件循环,研究了如何同时运行长耗时的操作,并探索了一些可以优化此操作的asyncioAPI。然而,到目前为止,我们只是用asyncio.sleep函数模拟了长时间的操作。由于我们想要构建的不仅是演示应用程序,因此我们将使用一些真实世界的阻塞操作......
  • C/C++学生成绩管理系统[2023-05-30]
    C/C++学生成绩管理系统[2023-05-30]学生成绩管理系统设计----高级语言课程设计题目问题描述:设学生信息包括:学号、姓名、期末成绩、平时成绩,对学生的学习成绩信息进行管理。设计要求:实现学生信息的录入、修改、插入、删除、查询、计算总评成绩、根据总评成绩排序和划分等级、......
  • c++类型转换
    C语言中的类型转换C语言和C++都是强类型语言,如果赋值运算符左右两侧变量的类型不同,或形参与实参的类型不匹配,或返回值类型与接收返回值的变量类型不一致,那么就需要进行类型转换。C语言中有两种形式的类型转换,分别是隐式类型转换和显式类型转换:隐式类型转换:编译器在编译阶段自......
  • web安全详解(渗透测试基础)
    一、Web基础知识1.http协议超文本传输协议是互联网上应用最广泛的一种网络协议。所有www文件都必须遵守的一个标准,是以ASCII码传输,建立在TCP/IP协议之上的应用层规范,简单点说就是一种固定的通讯规则。2.网络三种架构及特点网络应用程序架构包括三种:客户机/服务器结构(C/S)......
  • Kubernetes GoRoutineMap工具包代码详解
    1、概述GoRoutineMap定义了一种类型,可以运行具有名称的goroutine并跟踪它们的状态。它防止创建具有相同名称的多个goroutine,并且在上一个具有该名称的goroutine完成后的一段退避时间内可能阻止重新创建goroutine。使用GoRoutineMap场景:使用协程的方式运行函数逻辑,如果函......
  • C++ Primer 第一、二章 C++基础,变量和基本类型
    一、C++基础<iostream>包含两个基础类型,istream-输入流和ostrea-输出流。标准库定义了四个IO对象cin-标准输入(istream),cout-标准输出(o),cerr-标准错误(o),clog-用来输出程序运行时的一般性信息(o)。 #include<iostream>intmain(){std::cout<<"Enter"<<std:......
  • 第十二届蓝桥杯c++b组国赛题解(还在持续更新中...)
    试题A:带宽解题思路:由于小蓝家的网络带宽是200Mbps,即200Mb/s,所以一秒钟可以下载200Mb的内容,根据1B=8b的换算规则,所以200Mb=200/8MB=25MB。所以小蓝家的网络理论上每秒钟最多可以从网上下载25MB的内容。代码实现:#include<iostream>#include<algorithm>usingnamespacestd......
  • k8s探针详解
    一、探针类型介绍:(1)、K8s中存在三种类型的探针:livenessprobe、readinessprobe和startup探针。每类探针都支持三种探测方法liveness探针:影响的是单个容器,如果检查失败,将杀死容器,根据pod的restartPolicy来操作。readiness探针:影响的是整个pod,即如果pod中有多个容器,只要有一......
  • Multiserver游戏服务器Demo[C++&Lua]
    代码参考代码文件参考下述详解的类图,工程参考第零章工程说明关键特性对Socket库进行封装,抹平Socket的Window&Linux的平台差异。C++嵌入lua脚本,增加开发者编码效率,减少编译时间消耗。非阻塞网络IO多线程任务模型多服务模型详解Socket库封装主要是对C++的Socket库进行......