首页 > 系统相关 >面试必考 - 结构体内存对齐,还有人不会?

面试必考 - 结构体内存对齐,还有人不会?

时间:2022-11-06 19:32:02浏览次数:43  
标签:字节 必考 面试 内存 printf Test 对齐 结构


很多人在编写代码实现功能的时候,或多或少都会接触到结构体的使用,在很多的编语言中,结构体都是很多数据结构的重要的组成部分。

在嵌入式的项目开发中,很多时候芯片的内存资源都是有限的,为了代码更加的优化和高效,尽可能的合理使用内存资源,在使用结构体这类结构时,往往是要考虑结构所占的内存大小的。以此方便我们调整顺序,尽可能的节省内存资源。(土豪略过,不做讨论!)

使用结构体,需要考虑结构的内存对齐问题,现在逐一展开讲讲!

1、 什么是内存对齐?

我们都知道,定义的变量(元素)是要按照顺序一个一个放到内存中去的,它们也不一定就是紧密排列的,是要按照一定的规则就行排放的,这就是内存对齐。

对结构体来说,元素的存储从首地址开始,第一个元素的地址和整个结构体的首地址相同,其他的每个元素放置到内存中时,它都会认为内存是按照元素自己的大小来划分空间的,所以元素放置在内存中的位置一定会在元素自己宽度(字节数)的整数倍上开始,这就是所谓的结构体内存对齐问题。

特别有意思的是,C语言同意使用者自行确定内存对齐的设置,通过伪指令 #pragma pack (n) 可以重新设定内存对齐的字节数。这个后面会讲到!

2、 为什么要有内存对齐?

这真是一个好问题!从网上了解到的几个原因:

(1)考虑平台的原因。实际的硬件平台跑代码是有所区别的,一些硬件平台可以对任意地址上的任意数据进行访问,而有一些硬件平台就不行,就是有限制,所以内存对齐是一种解决办法。

(2)考虑性能的原因。CPU访问内存时,如果内存不对齐的话,为了访问到数据的话就需要几次访问,而对齐的内存只需要访问一次即可,提高了CPU访问内存的速度。

3、结构体的内存对齐规则是什么?

每当有用到结构体的时候,总会考虑这个结构体实际应该要占用多少的内存,是否还有优化的空间。特别是在面试时,结构体的内存对齐问题是很多面试会考到,也会经常被提及问起,属于高频考点了!

话不多说,直接奉上结构体的内存对齐的判别方法,方便大家快速算出结构体所占的内存大小。

这里先规定一下:内存对齐值称为内存对齐有效值,这个值可以是1、2、4、8、16,所以先规定一下。

规则:

规则1,结构体第一个成员一定是放在结构体内存地址里面的第1位。

规则2,成员对齐规则:除了第一个成员,之后的每个数据成员的对齐要按照成员自身的长度和内存对齐有效值进行比较,按两者中最小的那个进行对齐,即偏移的倍数。

规则3,结构体整体对齐规则:数据成员完成对齐之后,对整个结构体的大小进行对齐。按照结构体的大小必须要是内存对齐有效值和结构体中最大数据成员长度两者中的最小值的整数倍,不足的在后面补空。

4、 规则的验证

规则已经在上面摆出来了,那怎么知道对不对呢?那就只能现场分析一波。

举个例子:

编译器内存对齐有效值=4,结构体如下:

typedef struct 
{
int a;
char b;
}StructDef_t;

大家猜猜这个结构体占了多少个内存?

5个?

NO、NO、NO!!!

正确答案是:8个!

8个是怎么来的呢?假设地址从0开始,分析如下:

首先,a为int型占4个字节,放在最开始的位置,即offset=0的位置,放在0、1、2、3的地址。

然后,用规则2:b占一个字节,内存对齐有效值为4,所以b要相对于结构体首地址的偏移要为1的倍数,放在4的地址。

最后,从上面的一步我们知道了这个结构体内的成员对齐之后占了五个字节。用规则3:结构体内最大的成员占4个字节,内存对齐有效值为4,所以整个结构体的大小要为4的倍数,5不是4的倍数,所以要在后面补齐,为8个字节。

所以,最终这个结构体占用8个字节!

这个过程可以用下面的图示进行演示,方便加深了解,如下图:

面试必考 - 结构体内存对齐,还有人不会?_内存对齐

5、强化训练

如下:

#include<stdio.h>
typedef struct
{
int i;
char c1;
char c2;
}Test1;

typedef struct{
char c1;
int i;
char c2;
}Test2;

typedef struct{
char c1;
char c2;
int i;
}Test3;

int main()
{
printf("%d\n",sizeof(Test1)); // 输出8
printf("%d\n",sizeof(Test2)); // 输出12
printf("%d\n",sizeof(Test3)); // 输出8
return 0;
}

     这三个结构体,可以运用上面的三个规则去验证一遍。

注意:从上面的三个结构体中可以发现,通过调换结构体里面的数据成员的位置,可以改变结构体占空间的大小,这是因为数据元素位置不同,对齐之后的结果也不同。这种方式可以用于结构体的空间优化,通过调整元素的位置,减少内存的占用!

6、自定义内存的对齐值

C语言中是允许用户自己定义内存对齐值的,使用一个伪指令即可,如下:

#pragma pack (n)    // 自定义对齐值,n=1,2,4,8,16
#pragma pack ( ) // 取消自定义字节对齐

6.1、1 字节对齐

如下代码:

#include<stdio.h>

#pragma pack (1)

typedef struct
{
int a;
char b;
}StructDef_t;


int main()
{
StructDef_t Test;
printf("a addr = %x\r\n",&Test.a);
printf("b addr = %x\r\n",&Test.b);
printf("byte = %d\r\n",sizeof(Test));
}

#pragma pack ()

在1字节内存对齐情况下,这里的结构体占5个字节!

6.2、2 字节对齐

如下代码:

#include<stdio.h>

#pragma pack (2)

typedef struct
{
int a;
char b;
}StructDef_t;


int main()
{
StructDef_t Test;
printf("a addr = %x\r\n",&Test.a);
printf("b addr = %x\r\n",&Test.b);
printf("byte = %d\r\n",sizeof(Test));
}

#pragma pack ()

在2字节内存对齐情况下,这里的结构体占6个字节!

6.3、4 字节对齐

如下代码:

#include<stdio.h>

#pragma pack (1)

typedef struct
{
int a;
char b;
}StructDef_t;


int main()
{
StructDef_t Test;
printf("a addr = %x\r\n",&Test.a);
printf("b addr = %x\r\n",&Test.b);
printf("byte = %d\r\n",sizeof(Test));
}

#pragma pack ()

在4字节内存对齐情况下,这里的结构体占8个字节!

以此类推,可以自行验证!

面试必考 - 结构体内存对齐,还有人不会?_内存对齐_02




标签:字节,必考,面试,内存,printf,Test,对齐,结构
From: https://blog.51cto.com/u_15695002/5827534

相关文章

  • 数据分析面试题集锦(四)
    大家好,今天整理数据分析面试题集锦(四),经常会被问到,“数据分析需要学习什么技能?”,“针对实际的业务场景,如何使用数据分析工具去分析?”基于此作者总结数据分析面试常用的问题......
  • 35+,如果面试让我手写红黑树!
    一、前言:挂在树上!不知道你经历过HashMap的夺命连环问!为啥,面试官那么喜欢让你聊聊HashMap?因为HashMap涉及的东西广,用到的数据结构多,问题延展性好,一个HashMap就能聊下......
  • 21个Transformer面试题的简单回答 -- 加强版
    原文链接:https://jishuin.proginn.com/p/763bfbd565fc本文在原文基础框架上有增加,附上更详细或者正确的解答。1.Transformer为何使用多头注意力机制?(为什么不使用一个头)答......
  • 机器学习保姆级学习路线及面试
     作者:码农鬼仔链接:https://www.nowcoder.com/discuss/1059103来源:牛客网但鬼仔的这几篇笔记太零散了,想到哪写到哪,不利于同学们系统性地进行学习和准备算法岗的知识。在......
  • 深入理解Java内存区域(最新版面试题)
    1、什么是JVM?JVM(JavaVirtualMachine)是用于运行Java字节码的虚拟机,包括一套字节码指令集、一组程序寄存器、一个虚拟机栈、一个虚拟机堆、一个方法区和一个垃圾回收器。JVM......
  • 大厂面试,欢聚时代四年多经验的Java面经
    欢聚时代一面(1h)先做下自我介绍,固定环节面试官:既然你用Java语言,那我们先讲点Java基础的东西吧,你说下Java有哪些锁?按照机制区分的话,Java中包含的锁可以分为公平锁和非公平锁......
  • 【面试题】JS 常见的 6 种继承方式(常见)
    继承概念的探究说到继承的概念,首先要说一个经典的例子。先定义一个类(Class)叫汽车,汽车的属性包括颜色、轮胎、品牌、速度、排气量等,由汽车这个类可以派生出“轿车”和“货车......
  • 【面试题】 面试手写JS 十六题(必看)
     1、手写实现防抖和节流1.1实现防抖函数防抖函数原理:把触发非常频繁的事件合并成一次去执行 在指定时间内只执行一次回调函数,如果在指定的时间内又触发了该事件,则回调函......
  • 【面试题】面试小技巧:如果有人问你 xxx 技术是什么?
    背景在前几天,有一个朋友突然问了我一个问题,说如果有人问你“React是什么?你怎么回答。 ”,我当时脱口而出“React是一个网页UI框架一个,它的特点声明式、组件化、组件化、......
  • 【面试题】说说JS中的this指向问题
    JS中的this指向问题this的指向问题全局作用域在JS中,全局的变量和函数附着在​​global​​​对象上,全局对象在浏览器环境下是​​window​​对象。在全局作用域中,​​this​......