解析C语言中结构体struct的对齐问题

 更新时间:2016年04月20日 11:12:18   投稿:goldensun  
这篇文章主要介绍了C语言中结构体struct的对齐问题,作者深入到内存分配方面来进行解析,需要的朋友可以参考下

首先看一下结构体对齐的三个概念值:

数据类型的默认对齐值(自身对齐):
1.基本数据类型:为指定平台上基本类型的长度。如在32位机器中,char对齐值为1,short为2,int,float为4,double为8;
结构体:其数据成员中默认对齐值最大的那个值。
2.指定对齐值:#pragma pack (value)时的指定对齐值value。
3.数据类型的有效对齐值:默认对齐值和指定对齐值中小的那个值。
有了这些值,我们就可以很方便的来讨论具体数据结构的成员和其自身的对齐方式。有效对齐值N是最终用来决定数据存放地址方式的值,最重要。有效对齐N,就是表示“对齐在N上”,也就是说该数据的“偏移量%N=0”。而数据结构中的数据变量都是按定义的先后顺序来排放的。第一个数据变量的起始地址就是数据结构的起始地址。结构体的成员变量要对齐排放(对于非对齐成员需要在其前面填充一些字节,保证其在对齐位置上),结构体本身也要根据自身的有效对齐值圆整(就是结构体总长度需要是结构体有效对齐值的整数倍)。

通过上面的分析,对结构体进行字节对齐,我们需要知道四个值:

  • 指定对齐值:代码中指定的对齐值,记为packLen;
  • 默认对齐值:结构体中每个数据成员及结构体本身都有默认对齐值,记为defaultLen;
  • 成员偏移量:即相对于结构体起始位置的长度,记为offset;
  • 成员长度:结构体中每个数据成员的长度(注结构体成员为补齐之后的长度),记为memberLen。

及两个规则:

1.对齐规则:
offset % vaildLen = 0,其中vaildLen为有效对齐值vaildLen = min(packLen, defaultLen);

2.填充规则:
如成员变量不遵守对齐规则,则需要对其补齐;在其前面填充一些字节保证该成员对齐。需填充的字节数记为padLen:

padLen = getPadLen(offset , defaultLen);
int getPadLen(int offsetLen, int defaultLen)
{
  int vaildLen = min(packLen,defaultLen);
  if(0 == vaildLen || 0 == offsetLen % vaildLen)
  {
    return 0;
  }
  return vaildLen - (offsetLen % vaildLen);
}

结构体对齐算法思想:深度优先填充

先对齐内层结构体;
对每个数据成员计算其defaultLen、memberLen和offset;

再遍历每个数据成员时计算;
对于基本数据类型成员defaultLen=memberLen;对于结构体成员defaultLen等于它的所有成员的最大的memberLen;
遍历时对成员的memberLen进行累加,得到当前成员的offsetLen;
运用对齐及填充规则:在当前结构体成员前填充padLen个字节;


举例说明:

struct{

 short a;

 short b;

 short c; }A; sizeof(A) = 6; 

(vc6与gcc相同)

struct{

 long a;

 short c; }A; sizeof(A) = 8;

(vc6与gcc相同), 它的内存分配为: a1 a2 a3 a4 , c1 c2 x x(a1为a的第一个字节,x为补齐字节,下同)

struct{

int a;

char b;

short c; }A;

sizeof(A) = 8;

A的内存分配为:

 a1 a2 a3 a4, b1 x c1 c2
struct{

char a;

int b;

short c; }A1;

sizeof(A1) = 12;

(vc6与gcc相同)

A1的内存分配为:

a1 x x x, b1 b2 b3 b4, c1 c2 x x

下面是更复杂的情况,结构体作为成员

struct{

int a;

doubl b;

short c; }A; // sizeof(A) = 24 (vc6与gcc相同)

struct{

  char a,b;

int c;

double d;

short e;

struct A h;

}B;

sizeof(B) = 48 //(vc6与gcc相同)

A的内存分布:

a1 a2 a3 a4 x x x x, b1 b2 b3 b4 b5 b6 b7 b7, c1 c2 x x x x x x

B的内存分布:

a1 b1 x x, c1 c2 c3 c4 , d1 d2 d3 d4 d5 d6 d7 d8, e1 e2 x x x x 

相关文章

  • C++简单又轻松建立链式二叉树流程

    C++简单又轻松建立链式二叉树流程

    二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址
    2022-06-06
  • OpenMP深入剖析reduction子句教程

    OpenMP深入剖析reduction子句教程

    这篇文章主要为大家介绍了OpenMP深入剖析reduction子句教程,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • 深入C++拷贝构造函数的总结详解

    深入C++拷贝构造函数的总结详解

    本篇文章是对C++中拷贝构造函数进行了总结与介绍。需要的朋友参考下
    2013-05-05
  • 关于C语言函数strstr()的分析以及实现

    关于C语言函数strstr()的分析以及实现

    以下是对C语言中strstr()函数的使用进行了详细的分析介绍,需要的朋友可以参考下
    2013-07-07
  • C++中virtual继承的深入理解

    C++中virtual继承的深入理解

    本篇文章是对C++中的virtual继承进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • C语言驱动开发之内核文件的读写

    C语言驱动开发之内核文件的读写

    这篇文章主要为大家详细介绍了C语言驱动开发中内核文件的读写的系列函数,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-06-06
  • 浅谈C语言转义字符和格式控制符

    浅谈C语言转义字符和格式控制符

    下面小编就为大家带来一篇浅谈C语言转义字符和格式控制符。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-08-08
  • windows下用c++获取本机ip地址的三种方法

    windows下用c++获取本机ip地址的三种方法

    工作过程中遇到一个需求,需要获取本机ip地址,同时获取本机网络连接情况,即网线是否连接,经过多番搜索,本文给大家介绍了3种方案,通过代码示例介绍的非常详细,需要的朋友可以参考下
    2023-11-11
  • Qt之QTimer使用及技巧小结

    Qt之QTimer使用及技巧小结

    QTimer是Qt中的定时器类,用于执行定时操作,如在一段时间间隔后触发某个槽函数或执行特定的代码,下面就来介绍一下Qt之QTimer使用及技巧小结,感兴趣的可以了解一下
    2023-10-10
  • ACE反应器(Reactor)模式的深入分析

    ACE反应器(Reactor)模式的深入分析

    本篇文章是对ACE反应器(Reactor)模式进行了详细的分析介绍,需要的朋友参考下
    2013-05-05

最新评论