C/C++结构体内存粒度对齐?结合调试信息来看

简介: C/C++结构体内存粒度对齐?结合调试信息来看

C语言或者C++内存粒度对齐是我们经常提到的问题,而对内存的有效合理的利用,必然会使我们写出来的代码更加高效。这几天写代码过程中出现了一个bug,就是由于内存粒度原因导致,所以总结一下。


首先我们来看一下理论知识(我个人理解的):

结构体中数据成员内存对齐的原则:按照一个结构体中的成员中最大字节数整数倍对齐,比如在x86下,出现int(4字节) char(1字节) double(8字节),则肯定是按照最大的8字节整数倍对齐,8字节就相当于一个基准一样,如果遇到的字节数可以在8字节内存放,那就ok,否则需要重新申请8字节来存放,至于说是8的几倍,那需要看数据存放的顺序,内存满足多插少补的原则。


接下来我就结合代码和调试信息来说明内存粒度对齐的相关问题:

以下提到的测试数据,基于x86

eg1:

typedef struct _STRUCT_A_
{
  char a; 
  int  b;
  char c;
}STRUCT_A;

面对以上的一个结构体,初学者可能认为是1+4+1总共6个字节。那么我们来实际看看它的大小究竟是多少

image.png

它是12字节的大小,那么我们再来看看它的内存分布情况:

image.png

确实初始化为12个字节的0,那我们赋值字符a,int值5以及字符c之后,内存中又是如何存放的呢?

image.png

那我们可以如何优化这个结构体,让他它占有更少的内存呢?我们可以写成以下两种形式:

eg2:

typedef struct _STRUCT_A_
{
  int  b;
  char a; 
  char c;
}STRUCT_A;
typedef struct _STRUCT_A_
{
  char a; 
  char c;
  int  b;
}STRUCT_A;

我们再来看看内存中的情况以及结构体大小为多少:

image.png


image.png


以上证实了我们一开始的说法,当char存放占4字节基准为1字节,接下来的成员还是char,拿它就可以继续存放,存放第二个char之后,还有2字节空余,但是遇到了4字节的int,不够了,只能存放在另外的4字节内存中了。

那我们有没有办法,就是不管我们怎么存放,让它都有固定的内存对齐粒度呢?当然是可以的:

eg3:

#pragma pack(push)
#pragma pack(2)
typedef struct _STRUCT_A_
{
  char a;
  int  b;
  char c;
}STRUCT_A;
#pragma pack(pop)

我们可以使用以上代码,使内存粒度对齐按照2字节对齐,我们来验证一下:

image.png

image.png

当然也可以按照1字节对齐,只需要修改pack中的值为1,如下:

eg4:

#pragma pack(push)
#pragma pack(1)
typedef struct _STRUCT_A_
{
  char a;
  int  b;
  char c;
}STRUCT_A;
#pragma pack(pop)

image.png

image.png

但是我们在实际情况中,可能会遇到更加复杂点的情况,比如结构体的成员是结构体或者联合体。这种情况又是如何对齐的呢?我们来看一个稍微复杂一点的结构体:

eg5:

typedef struct _STRUCT_A_
{
  uint32_t a;
  uint32_t b;
}STRUCT_A;
typedef union _UNION_A_ {
  char*  m1;
  STRUCT_A m2;
}UNION_A;
typedef struct _STRUCT_B_
{
  UNION_A a;
  UNION_A  b;
  UNION_A c;
  UNION_A d;
  uint16_t e;//2字节
}STRUCT_B;

按照我们的想法,那应该UNION_A所占内存大小为8字节,那么STRUCT_B应该按照8字节对齐,那么5个数据成员,大小应该使5*8=40字节,但是实际情况好像并不是这样:

image.png

怎么会出现36这个情况呢?原因出现在STRUCT_A中,虽然unionA的大小确实为8字节,但是其8字节的主要原因是STRUCT_A是8字节,那STRUCT_A中是两个4字节的成员,所以内存粒度对齐还是4字节,这样就不难理解最后的STRUCT_B为36字节了,其中前4个成员是32字节,最后一个是2字节,但是按照4字节对齐,所以是36字节。


“山不向我走来,我便向它走去”


目录
相关文章
|
3天前
|
存储 编译器 C语言
C++中的内存管理
C++中的内存管理
15 0
|
5天前
|
存储 Linux C语言
【C++从练气到飞升】07---内存管理
【C++从练气到飞升】07---内存管理
|
6天前
|
存储 算法 数据安全/隐私保护
【C++入门到精通】 哈希结构 | 哈希冲突 | 哈希函数 | 闭散列 | 开散列 [ C++入门 ]
【C++入门到精通】 哈希结构 | 哈希冲突 | 哈希函数 | 闭散列 | 开散列 [ C++入门 ]
7 0
|
7天前
|
存储 编译器 C++
【C++】内存管理和模板基础(new、delete、类及函数模板)
【C++】内存管理和模板基础(new、delete、类及函数模板)
21 1
|
19天前
|
存储 缓存 算法
C++从入门到精通:4.6性能优化——深入理解算法与内存优化
C++从入门到精通:4.6性能优化——深入理解算法与内存优化
|
19天前
|
存储 程序员 编译器
C++从入门到精通:3.4深入理解内存管理机制
C++从入门到精通:3.4深入理解内存管理机制
|
19天前
|
存储 搜索推荐 C++
【C++高阶(二)】熟悉STL中的map和set --了解KV模型和pair结构
【C++高阶(二)】熟悉STL中的map和set --了解KV模型和pair结构
|
19天前
|
存储 人工智能 程序员
【重学C++】【内存】关于C++内存分区,你可能忽视的那些细节
【重学C++】【内存】关于C++内存分区,你可能忽视的那些细节
54 1
|
19天前
|
C语言 C++
【C++基础(九)】C++内存管理--new一个对象出来
【C++基础(九)】C++内存管理--new一个对象出来
|
21天前
|
存储 编译器 Linux
c++的学习之路:8、内存管理与模板
c++的学习之路:8、内存管理与模板
11 0