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

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

数据类型的默认对齐值(自身对齐):
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语言
, 结构体
, struct
, 对齐
结构体对齐
c语言结构体对齐、c语言结构体字节对齐、c语言结构体内存对齐、struct stat结构体、struct file 结构体,以便于您获取更多的相关知识。

时间: 2024-09-13 15:18:05

解析C语言中结构体struct的对齐问题_C 语言的相关文章

C语言中结构体struct编写的一些要点解析_C 语言

一.关于结构体的声明1.匿名声明.如: struct { int i,j; }point; 说明: 这段代码的含义是,声明一个无名(anonymous)的结构体,并创建了一个结构体变量point.如果这段声明是放在全局域(在任意函数(比如main函数)外)内,那么point内的变量将被初始化为默认值,换句话说,以这种方式声明结构体变量时就已经为它分配了内存空间. 适用于该结构体只需要产生一个变量!本例中,该匿名结构体将有且仅有point这个结构体变量! 不同的匿名结构体变量,类型是不同的!如 s

C语言中结构体(struct)的几种初始化方法_C 语言

本文给大家总结的struct数据有3种初始化方法      1.顺序      2.C风格的乱序      3.C++风格的乱序 下面通过示例代码详细介绍这三种初始化方法. 1)顺序 这种方法很常见,在一般的介绍C的书中都有介绍.顺序初始化的特点是: 按照成员定义的顺序,从前到后逐个初始化:允许只初始化部分成员:在被初始化的成员之前,不能有未初始化的成员. 示例: struct User oneUser = {10, "Lucy", "/home/Lucy"}; 2

struct-C语言中结构体中的数组,不能直接赋值吗

问题描述 C语言中结构体中的数组,不能直接赋值吗 设有定义:struct{char mark[12];intnum1;double num2;}t1,t2;若变量均已正确赋初值,则以下语句中错误的是(C) (A) t1=t2; (B) t2.num1=t1.num1; (C) t2.mark=t1.mark;//mark为结构体中的数组,不能直接赋值?? (D) t2.num2=t1.num2; ?====如题参考答案说为结构体中的数组,不能直接赋值,为什么呢?那应该怎么赋值呢?求大侠指教 解决

c语言中结构体对齐详解

为什么要对齐?     现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐.     对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同.一些平台对某些特定类型的数据只能从某些特定地址开始存取.比如有些架构的CPU在访问 一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保

详解C语言中结构体的自引用和相互引用_C 语言

结构体的自引用(self reference),就是在结构体内部,包含指向自身类型结构体的指针. 结构体的相互引用(mutual reference),就是说在多个结构体中,都包含指向其他结构体的指针.1. 自引用 结构体 1.1 不使用typedef时错误的方式: struct tag_1{ struct tag_1 A; /* 结构体 */ int value; };         这种声明是错误的,因为这种声明实际上是一个无限循环,成员b是一个结构体,b的内部还会有成员是结构体,依次下去

详解C语言中的内存四区模型及结构体对内存的使用_C 语言

内存四区 1.代码区代码区code,程序被操作系统加载到内存的时候,所有的可执行代码都加载到代码区,也叫代码段,这块内存是不可以在运行期间修改的.2.静态区所有的全局变量以及程序中的静态变量都存储到静态区.3.栈区栈stack是一种先进后出的内存结构,所有的自动变量,函数的形参都是由编译器自动放出栈中,当一个自动变量超出其作用域时,自动从栈中弹出.对于自动变量,什么时候入栈,什么时候出栈,是不需要程序控制的,由C语言编译器.实现栈不会很大,一般都是以K为单位的. 当栈空间以满,但还往栈内存压变量

C语言中的结构体的入门学习教程_C 语言

C语言中数组允许定义类型的变量,可容纳相同类型的多个数据项,但结构体在C语言编程中,它允许定义不同种类的数据项可供其他用户定义的数据类型. 结构是用来代表一个记录,假设要跟踪图书馆的书籍.可能要跟踪有关每本书以下属性: Title - 标题 Author - 作者 Subject - 科目 Book ID - 编号 定义结构体定义一个结构体,必须使用结构体的struct语句.该struct语句定义了一个新的数据类型,程序不止一个成员.struct语句的格式是这样的: struct [struct

C语言中结构体偏移及结构体成员变量访问方式的问题讨论_C 语言

c语言结构体偏移 示例1 我们先来定义一下需求: 已知结构体类型定义如下: struct node_t{ char a; int b; int c; }; 且结构体1Byte对齐 #pragma pack(1) 求: 结构体struct node_t中成员变量c的偏移. 注:这里的偏移量指的是相对于结构体起始位置的偏移量. 看到这个问题的时候,我相信不同的人脑中浮现的解决方法可能会有所差异,下面我们分析以下几种可能的解法: 方法1 如果你对c语言的库函数比较熟悉的话,那么你第一个想到的肯定是of

深入解析C语言中函数指针的定义与使用_C 语言

1.函数指针的定义    函数是由执行语句组成的指令序列或者代码,这些代码的有序集合根据其大小被分配到一定的内存空间中,这一片内存空间的起始地址就成为函数的地址,不同的函数有不同的函数地址,编译器通过函数名来索引函数的入口地址,为了方便操作类型属性相同的函数,c/c++引入了函数指针,函数指针就是指向代码入口地址的指针,是指向函数的指针变量. 因而"函数指针"本身首先应该是指针变量,只不过该指针变量指向函数.这正如用指针变量可指向整形变量.字符型.数组一样,这里是指向函数.C在编译时,