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

所属分类: 软件编程 / C 语言 阅读数: 45
收藏 0 赞 0 分享

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

数据类型的默认对齐值(自身对齐):
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语言来求最大连续子序列乘积的方法,基本的思路以外文中还附有相关ACM题目,需要的朋友可以参考下
收藏 0 赞 0 分享

用C语言判断一个二叉树是否为另一个的子结构

这篇文章主要介绍了用C语言判断一个二叉树是否为另一个的子结构,是数据结构学习当中的基础知识,需要的朋友可以参考下
收藏 0 赞 0 分享

C语言实现的阶乘,排列和组合实例

这篇文章主要介绍了C语言实现的阶乘,排列和组合的方法,涉及C语言数学运算的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
收藏 0 赞 0 分享

C语言查找数组里数字重复次数的方法

这篇文章主要介绍了C语言查找数组里数字重复次数的方法,涉及C语言针对数组的遍历与判断技巧,具有一定参考借鉴价值,需要的朋友可以参考下
收藏 0 赞 0 分享

C语言简单实现计算字符个数的方法

这篇文章主要介绍了C语言简单实现计算字符个数的方法,涉及C语言针对字符串的简单遍历与判定技巧,具有一定参考借鉴价值,需要的朋友可以参考下
收藏 0 赞 0 分享

c实现linux下的数据库备份

本文给大家简单介绍下c实现linux下的数据库备份的方法和具体的源码,十分的实用,有需要的小伙伴可以参考下。
收藏 0 赞 0 分享

C++获得文件状态信息的方法

这篇文章主要介绍了C++获得文件状态信息的方法,包括文件状态信息、文件所在磁盘盘符、文件创建时间、访问时间及修改日期等,需要的朋友可以参考下
收藏 0 赞 0 分享

C语言按关键字搜索文件夹中文件的方法

这篇文章主要介绍了C语言按关键字搜索文件夹中文件的方法,涉及C语言文件操作及字符串查找的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
收藏 0 赞 0 分享

C语言之字符串模糊查询方法的实现

本篇文章主要为大家介绍字符串模糊查询的C语言程序编写方法,有需要的朋友可以参考下
收藏 0 赞 0 分享

C语言实现BMP转换JPG的方法

这篇文章主要介绍了C语言实现BMP转换JPG的方法,涉及C#图片格式转换的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
收藏 0 赞 0 分享
查看更多