内存对齐--面试常问问题和笔试常考问题

news2024/11/23 22:28:10

1.内存对齐的意义

C++ 内存对齐的主要意义可以简练概括为以下几点:

  1. 提高访问效率:内存对齐可以使数据在内存中以更加紧凑的方式存储,从而提高了数据的访问效率。处理器通常能够更快地访问内存中对齐的数据,而不需要额外的字节偏移计算。

  2. 硬件要求:许多硬件平台要求数据按照一定的对齐规则存储,否则可能会导致性能下降或者错误。不符合硬件要求的数据存储方式可能会引发总线错误或性能降低。

  3. 结构体和类的正确性:在C++中,结构体和类中的成员变量通常按照编译器的默认对齐方式进行排列,以确保数据的正确访问和存储。手动调整对齐方式可以保证数据的正确性。

  4. 跨平台开发:内存对齐可以确保数据在不同平台上的一致性。这对于跨平台开发非常重要,因为不同的硬件架构可能有不同的对齐要求。

  5. 节省内存:内存对齐可以减少内存碎片,从而节省内存空间。当数据按照对齐要求存储时,不会出现因为填充字节而浪费内存的情况。

总之,C++ 内存对齐的主要意义在于提高访问效率、符合硬件要求、确保数据的正确性、支持跨平台开发以及节省内存空间。通过遵循对齐规则,可以充分利用硬件的性能优势,并确保程序在不同平台上的可移植性和正确性。

2.对齐原则


原则1 :数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在
offiset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身
长度中,比较小的那个进行。(先偏移到那个对齐标准数的指定倍数,在进行加上本身)
原则2:结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进
行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的
那个进行。
原则3 :结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元
素大小的整数倍地址开始存储。

3.默认对齐值

默认对齐值:
Linux默认#pragma pack(4)
window默认#pragma pack(8)
注:可以通过预编译命令#pragma pack(n) , n=1,2,4,8,16来改变这一系数,其中的n就是指定
的“对齐系数”。

例题1:

#include <iostream>
#include <vector>
#include <algorithm>
#pragma pack(1)
using namespace std;

struct AA
{

    int a;   //长度4>1 按照1对齐,偏移量为0,存放位置区间[0,3]
    char b;  //长度1==1 按1 对齐,偏移量为4,存放位置区间[4]
    short c; //长度2>1,按1对齐,偏移量提升到2的 倍数6,存放位置区间[5,6]
    char d;  //长度1==1,按1 对齐,偏移量为6,存放位置区间[7]

    //整体存放【0-7】 位置中,共八个字节。
};

int main()
{
    cout << sizeof(AA) << endl;
    system("pause");
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#pragma pack(2)
using namespace std;

struct AA
{

    int a;   //长度4>1 按照1对齐,偏移量为0,存放位置区间[0,3]
    char b;  //长度1==1 按1 对齐,偏移量为4,存放位置区间[4]
    short c; //长度2>1,按1对齐,偏移量,存放位置区间[5,6]
    char d;  //长度1==1,按1 对齐,偏移量为6,存放位置区间[7]

    //整体存放【0-7】 位置中,共八个字节。
};

struct BB
{

    // BB 是注释掉以上 内容 按照2个字节对齐的情况
    int a;   //长度4>2 按照2对齐,偏移量为0,存放位置区间[0,3]
    char b;  //长度2>1 按1 对齐,偏移量为4,存放位置区间[4]
    short c; //长度2=1,按2对齐,整体偏移到2的倍数6,存放位置区间[6,7]
    char d;  //长度2>1,按1对齐,偏移量为7,存放位置区间[8],共9个字节。

    //整体存放【0-8】 位置中,共9个字节。
};

int main()
{

    // cout << sizeof(AA) << endl;
    cout << sizeof(BB) << endl;
    system("pause");
    return 0;
}

  

 

#include <iostream>
#include <vector>
#include <algorithm>
#pragma pack(4)
using namespace std;

struct AA
{

    int a;   //长度4>1 按照1对齐,偏移量为0,存放位置区间[0,3]
    char b;  //长度1==1 按1 对齐,偏移量为4,存放位置区间[4]
    short c; //长度2>1,按1对齐,偏移量,存放位置区间[5,6]
    char d;  //长度1==1,按1 对齐,偏移量为6,存放位置区间[7]

    //整体存放【0-7】 位置中,共八个字节。
};

struct BB
{

    // BB 是注释掉以上 内容 按照2个字节对齐的情况
    int a;   //长度4>2 按照2对齐,偏移量为0,存放位置区间[0,3]
    char b;  //长度2>1 按1 对齐,偏移量为4,存放位置区间[4]
    short c; //长度2=1,按2对齐,整体偏移到2的倍数6,存放位置区间[6,7]
    char d;  //长度2>1,按1对齐,偏移量为7,存放位置区间[8],共9个字节。

    //整体存放【0-8】 位置中,共9个字节。
};

struct CC
{

    int a;   //长度4=4 按照4对齐,偏移量为0,存放位置区间[0,3]
    char b;  //长度4>1 按照1对齐,偏移量为4,存放区间[4]
    short c; //长度 2<4 按照两个字节对齐,对齐到2的倍数6 存放位置{6,7}
    char d;  // 1<4 ,按照1 对齐。偏移量为7.存放位置的区间为[8],总大小为9
};

int main()
{

    // cout << sizeof(AA) << endl;
    // cout << sizeof(BB) << endl;
    cout << sizeof(CC) << endl;
    system("pause");
    return 0;
}

 

8字节对齐

#include <iostream>
#include <vector>
#include <algorithm>
#pragma pack(8)
using namespace std;

struct AA
{

    int a;   //长度4>1 按照1对齐,偏移量为0,存放位置区间[0,3]
    char b;  //长度1==1 按1 对齐,偏移量为4,存放位置区间[4]
    short c; //长度2>1,按1对齐,偏移量,存放位置区间[5,6]
    char d;  //长度1==1,按1 对齐,偏移量为6,存放位置区间[7]

    //整体存放【0-7】 位置中,共八个字节。
};

struct BB
{

    // BB 是注释掉以上 内容 按照2个字节对齐的情况
    int a;   //长度4>2 按照2对齐,偏移量为0,存放位置区间[0,3]
    char b;  //长度2>1 按1 对齐,偏移量为4,存放位置区间[4]
    short c; //长度2=1,按2对齐,整体偏移到2的倍数6,存放位置区间[6,7]
    char d;  //长度2>1,按1对齐,偏移量为7,存放位置区间[8],共9个字节。

    //整体存放【0-8】 位置中,共9个字节。
};

struct CC
{

    int a;   //长度4=4 按照4对齐,偏移量为0,存放位置区间[0,3]
    char b;  //长度4>1 按照1对齐,偏移量为4,存放区间[4]
    short c; //长度 2<4 按照两个字节对齐,对齐到2的倍数6 存放位置{6,7}
    char d;  // 1<4 ,按照1 对齐。偏移量为7.存放位置的区间为[8],总大小为9
};

struct DD
{

    int a;   // 4<8  按4对齐, 偏移:0 位置 {0,3}
    char b;  // 1<8 按1对齐 偏移:4 位置:{4}
    short c; // 2<8 按照2 对齐 偏移 6  位置 {6,7}
    char d;  // 1<8  按照1 对齐 偏移为7 位置[8] 总大小为9
};

int main()
{

    // cout << sizeof(AA) << endl;
    // cout << sizeof(BB) << endl;
    // cout << sizeof(CC) << endl;
    cout << sizeof(DD) << endl;
    system("pause");
    return 0;
}

#按照8位,有 包含 double的情况。

#include <iostream>
#include <vector>
#include <algorithm>
#pragma pack(8)
#include <stddef.h>
using namespace std;

struct AA
{

    int a;   //长度4>1 按照1对齐,偏移量为0,存放位置区间[0,3]
    char b;  //长度1==1 按1 对齐,偏移量为4,存放位置区间[4]
    short c; //长度2>1,按1对齐,偏移量,存放位置区间[5,6]
    char d;  //长度1==1,按1 对齐,偏移量为6,存放位置区间[7]

    //整体存放【0-7】 位置中,共八个字节。
};

struct BB
{

    // BB 是注释掉以上 内容 按照2个字节对齐的情况
    int a;   //长度4>2 按照2对齐,偏移量为0,存放位置区间[0,3]
    char b;  //长度2>1 按1 对齐,偏移量为4,存放位置区间[4]
    short c; //长度2=1,按2对齐,整体偏移到2的倍数6,存放位置区间[6,7]
    char d;  //长度2>1,按1对齐,偏移量为7,存放位置区间[8],共9个字节。

    //整体存放【0-8】 位置中,共9个字节。
};

struct CC
{
    int a;   //长度4=4 按照4对齐,偏移量为0,存放位置区间[0,3]
    char b;  //长度4>1 按照1对齐,偏移量为4,存放区间[4]
    short c; //长度 2<4 按照两个字节对齐,对齐到2的倍数6 存放位置{6,7}
    char d;  // 1<4 ,按照1 对齐。偏移量为7.存放位置的区间为[8],总大小为9
};

struct DD
{

    int a;   // 4<8  按4对齐, 偏移:0 位置 {0,3}
    char b;  // 1<8 按1对齐 偏移:4 位置:{4}
    short c; // 2<8 按照2 对齐 偏移 6  位置 {6,7}
    char d;  // 1<8  按照1 对齐 偏移为7 位置[8] 总大小为9
};

struct EE
{

    int a;    // 4<8  按4对齐, 偏移:0 位置 {0,3}
    double b; // 8==8 按8对齐 偏移量偏移到8的倍数 偏移8 位置:{8,16}
    short c;  // 2<8 按照2 对齐 偏移 16  位置 {16,17}
    char d;   // 1<8  按照1 对齐 偏移为17 位置[18] 总大小为9
};

int main()
{

    // cout << sizeof(AA) << endl;
    // cout << sizeof(BB) << endl;
    // cout << sizeof(CC) << endl;
    // cout << sizeof(DD) << endl;
    cout << sizeof(EE) << endl;
    cout << offsetof(EE, b) << endl; //查看偏移了多少内存。
    system("pause");
    return 0;
}

 例四:结构体包含结构体的运算。

#include <iostream>
#include <vector>
#include <algorithm>
#pragma pack(8)
#include <stddef.h>
using namespace std;

struct AA
{

    int a;   //长度4>1 按照1对齐,偏移量为0,存放位置区间[0,3]
    char b;  //长度1==1 按1 对齐,偏移量为4,存放位置区间[4]
    short c; //长度2>1,按1对齐,偏移量,存放位置区间[5,6]
    char d;  //长度1==1,按1 对齐,偏移量为6,存放位置区间[7]

    //整体存放【0-7】 位置中,共八个字节。
};

struct BB
{

    // BB 是注释掉以上 内容 按照2个字节对齐的情况
    int a;   //长度4>2 按照2对齐,偏移量为0,存放位置区间[0,3]
    char b;  //长度2>1 按1 对齐,偏移量为4,存放位置区间[4]
    short c; //长度2=1,按2对齐,整体偏移到2的倍数6,存放位置区间[6,7]
    char d;  //长度2>1,按1对齐,偏移量为7,存放位置区间[8],共9个字节。

    //整体存放【0-8】 位置中,共9个字节。
};

struct CC
{
    int a;   //长度4=4 按照4对齐,偏移量为0,存放位置区间[0,3]
    char b;  //长度4>1 按照1对齐,偏移量为4,存放区间[4]
    short c; //长度 2<4 按照两个字节对齐,对齐到2的倍数6 存放位置{6,7}
    char d;  // 1<4 ,按照1 对齐。偏移量为7.存放位置的区间为[8],总大小为9
};

struct DD
{

    int a;   // 4<8  按4对齐, 偏移:0 位置 {0,3}
    char b;  // 1<8 按1对齐 偏移:4 位置:{4}
    short c; // 2<8 按照2 对齐 偏移 6  位置 {6,7}
    char d;  // 1<8  按照1 对齐 偏移为7 位置[8] 总大小为9
};

struct EE
{

    int a;    // 4<8  按4对齐, 偏移:0 位置 {0,3}
    double b; // 8==8 按8对齐 偏移量偏移到8的倍数 偏移8 位置:{8,16}
    short c;  // 2<8 按照2 对齐 偏移 16  位置 {16,17}
    char d;   // 1<8  按照1 对齐 偏移为17 位置[18] 总大小为9
};

//=============================================================
struct GG
{

    //结构体内部最大元素为int.由于偏移量8刚好是4 的倍数,所以从8 开始存放struct 对应了规则三。
    int a1;   // 4<8   4  8   [8,11]
    char b1;  // 1<8  1  12  [12]
    short c1; // 2<8   2  14  [14,15]
    char d1;  // 1 <8   1  16  [16]
};
struct FF
{

    int a;   // 4<8 按4   偏移0 存放的位置【0,3】
    char b;  // 1<8 按1   偏移4           [4]
    short c; // 2<8  2      6            [6,7]

    GG g;

    //子strcut整体对齐系数=min((max(int,short,char),8))=4. 将内存补齐到4 的整数倍 20.

    char d; // 1<8  1   21  21

    //整体对齐系数 4 所有有21 补到24.
};
//===========================================
int main()
{

    // cout << sizeof(AA) << endl;
    // cout << sizeof(BB) << endl;
    // cout << sizeof(CC) << endl;
    // cout << sizeof(DD) << endl;
    // cout << sizeof(EE) << endl;
    // cout << offsetof(EE, b) << endl; //查看偏移了多少内存。

    cout << sizeof(FF) << endl;
    // cout << offsetof(FF, GG) << endl;

    system("pause");
    return 0;
}

 

 

 4.练习:

        

#include <iostream>
#include <vector>
#include <algorithm>
#pragma pack(8)
using namespace std;

struct A
{

    int a; // [0,4]
    double b;
    // [ 8, 16 ]
    float c;
    // [ 17, 20 ]
};
// #24

struct B
{

    char e[2]; // 1<8 按照2对齐  偏移 0  位置【0,1】
    short h;   // 2<8 2             2       [2,4]

    A a; // 24

    // 一共28 偏移一起达到32.
};

int main()
{
    cout << sizeof(B) << endl;
    system("pause");
    return 0;
}

 

 

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

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

相关文章

hadoop组件HDFS

HDFS里面的几个组件&#xff0c;分别有哪些功能和作用&#xff1f; Namenode:主角色,负责和客户端进行沟通.Datanode:从角色,负责存储数据Secondary namenode:秘书,服务器数据的收集&#xff0c;将信息传递给namenode注&#xff1a;Namenode宕机时集群会通过选举机制&#xff…

vue安装依赖报错install i 报错提示npm audit fix --force,or `npm audit` for details

vue项目执行npm install初始化后报错 run npm audit fix to fix them, or npm audit for details 出现这类提醒&#xff0c;按照如下操作进行 1、首先安装模块依赖&#xff1a; npm install &#xff08;npm audit fix 含义&#xff1a; 检测项目依赖中的漏洞并自动安装需要…

Java笔记三

包机制&#xff1a; 为了更好地组织类&#xff0c;Java提供了包机制&#xff0c;用于区别类名的命名空间。 包语句的语法格式为&#xff1a;pack pkg1[. pkg2[. pkg3...]]; 般利用公司域名倒置作为包名&#xff1b;如com.baidu.com&#xff0c;如图 导包&#xff1a; 为了能够…

协议-TCP协议-基础概念03-Keep live保活机制-TCP RST-TCP连接

Keep live保活机制-TCP RST-TCP连接 参考来源&#xff1a; 《极客专栏-网络排查案例课》 Keep live保活机制 定时发送心跳探测包&#xff1b; 对于心跳回复包有超时限制&#xff1b; 要打开这个 TCP Keep-alive 特性&#xff0c;你需要使用 setsockopt() 系统调用&#xff0…

Ps:缩放工具

缩放工具 Zoom Tool 常用于对图像进行视图上的放大和缩小。在查看图像细节、处理图像时极为常用。 快捷键&#xff1a;Z ◆ ◆ ◆ 常用操作方法与技巧 1、快捷键 Z 是一个弹簧键。即&#xff0c;在其它工具的状态下&#xff0c;按住 Z 键不放就会临时切换到缩放工具&#xff…

什么是异步编程?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 处理异步操作的方法⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打…

PHP8的继承和多态-PHP8知识详解

我们在前面的时候讲过《面向对象编程的特点》时&#xff0c;面向对象编程具有3大特点&#xff1a;封装性、继承性和多态性。 继承和多态的根本作用就是完成代码的重用。下面就来讲解php8的继承和多态。 1继承 子类可以继承父类的所有成员变量和成员方法&#xff0c;包括构造方…

Spring Boot与Spring Security的跨域解决方案

目录 一、什么是跨域问题 二、Spring Boot和Spring Security介绍 三、如何解决Spring Boot与Spring Security的跨域问题 一、什么是跨域问题 跨域问题&#xff08;Cross-Origin Resource Sharing&#xff0c;简称CORS&#xff09;是指在Web开发中&#xff0c;浏览器出于安全…

美轮美奂,尽在眼前——Aerial for Mac 高清鸟瞰屏保程序

想要让您的 Mac 屏幕焕发别样风采&#xff1f;那么&#xff0c;Aerial for Mac 高清鸟瞰屏保程序一定不容错过。这款应用程序将为您带来最优质的高清鸟瞰视频壁纸&#xff0c;让您的屏幕焕发无限活力和美感。 Aerial for Mac 高清鸟瞰屏保程序是一款专为 Mac 设计的屏幕保护程…

Unity之Hololens开发如何实现UI交互

一.前言 什么是Hololens? Hololens是由微软开发的一款混合现实头戴式设备,它将虚拟内容与现实世界相结合,为用户提供了沉浸式的AR体验。Hololens通过内置的传感器和摄像头,能够感知用户的环境,并在用户的视野中显示虚拟对象。这使得用户可以与虚拟内容进行互动,将数字信…

Vue组件库Element

目录 Vue组件库ElementElement简介Element快速入门环境配置Element常用组件Table表格Table表格演示Table表格属性详解 Pagination分页Pagination分页演示Pagination分页属性详解Pagination分页事件详解 Dialog对话框Dialog对话框组件演示Dialog对话框属性详解 Form表单Form表单…

两横一纵 | 寅家科技发布10年新征程战略

2023年9月22日&#xff0c;寅家科技“寅路向前”10年新征程战略发布会在上海举办&#xff0c;来自投资领域的东方富海、深创投、高新投等知名投资机构&#xff0c;一汽大众、一汽红旗、奇瑞汽车等主机厂&#xff0c;国家新能源汽车技术创新中心、梅克朗、芯驰科技、思特威等合作…

【湖科大教书匠】计算机网络随堂笔记第6章(计算机网络应用层)

目录 6.1、应用层概述 常见的应用 ​编辑 总结 ​编辑 6.2、客户/服务器方式&#xff08;C/S方式&#xff09;和对等方式&#xff08;P2P方式&#xff09; 概念 客户/服务器方式&#xff08;C/S方式&#xff09; 对等方式&#xff08;P2P方式&#xff09; 总结 6.3、动态主机配…

Spring 学习(六)代理模式

10. 代理模式 案例 10.1 静态代理 角色分析 抽象角色&#xff1a;一般使用接口或者抽象类实现。真实角色&#xff1a;被代理的角色。代理角色&#xff1a;代理真实角色&#xff0c;含附属操作。客户&#xff1a;访问代理对象的角色。 租房案例 定义租赁接口 /*** TODO* 租房*…

uniapp实现点击按钮分享给好友

<button class"share" open-type"share">分享</button>import {onLoad,onShareAppMessage,onShareTimeline} from dcloudio/uni-app onLoad(() > {//设置Menus菜单&#xff0c;使 发送给朋友/分享到朋友圈 两个按钮可以使用wx.showShareMen…

熟悉MySQL OCP和Oracle OCP和考试真实界面

解答OCP学员常问姚远老师的问题如下: 考试需要提前多久到达&#xff1f;&#xff08;提前15到30分钟到达&#xff09;考试需要带什么证件&#xff1f;&#xff08;考试必须携带2个证件&#xff1a;身份证另外一种证件。另外一种证件可以是&#xff1a;信用卡、护照、驾驶证、港…

【QT】QT事件Event大全

很高兴在雪易的CSDN遇见你 &#xff0c;给你糖糖 欢迎大家加入雪易社区-CSDN社区云 前言 本文分享QT中的事件Event技术&#xff0c;主要从QT事件流程和常用QT事件方法等方面展开&#xff0c;希望对各位小伙伴有所帮助&#xff01; 感谢各位小伙伴的点赞关注&#xff0c;小易…

解决cocoapods下载hermes太慢的问题

最近,在执行pod install命令安装iOS依赖包的时,运行到installing hermes engine 就直接卡住了。执行pod install --verbose 时,看到下载包的大小478M,但是下载速度高达 20kb/s。 对于这个问题,查阅了网上的一些资料,以下是一个可行的解决方案。 步骤1 打开node_modules…

11.2.0.4Oracle rac grid卸载安装注意事项

还有三天放国庆和中秋了&#xff0c;今天周一上班就跟丢了魂一样&#xff0c;本来两台11g RAC一个半小时搞定的事情&#xff0c;我从早上九点一直干到现在晚上八点半才干完&#xff0c;简直是昏了头了。安装的时候将大页设置错误&#xff0c;导致一套库直接系统崩了&#xff0c…

SpringBoot整合QQ邮箱发送验证码

1.项目介绍 基于SpringBoot QQ邮箱服务 Hutools实现的获取验证码功能&#xff0c;接下来从如何申请授权码&#xff0c;如何配置项目&#xff0c;如何启动项目&#xff0c;如何测试项目进行讲解&#xff0c;下面的图片是一个测试案例&#xff0c;使用postman进行测试&#xf…