结构体 字节对齐

转自:http://www.cnblogs.com/longlybits/articles/2385343.html   (有改动)

内存对齐

在用sizeof运算符求某结构体所占空间时,并不是简单地将结构体中所有元素各自占的空间相加,这里涉及到内存字节对齐的问题。从理论上讲,对于任何变量的访问都可以从任何地址开始访问,但是事实上不是如此,实际上访问特定类型的变量只能在特定的地址访问,这就需要各个变量在空间上按一定的规则排列,而不是简单地顺序排列,这就是内存对齐。

内存对齐的原因:

1)某些平台只能在特定的地址处访问特定类型的数据;

2)提高存取数据的速度。比如有的平台每次都是从偶地址处读取数据,对于一个int型的变量,若从偶地址单元处存放,则只需一个读取周期即可读取该变量;但是若从奇地址单元处存放,则需要2个读取周期读取该变量。

对齐策略

使用下面这条指令可以查看当前的 packing alignment(默认的对齐参数)

#pragma pack(show)

数据对齐的规则:“在自身对齐参数 和 指定对齐参数 中,选择小的对齐”

- 自身对齐参数:

1) 数据成员:数据成员的类型所占字节的长度

2) 复杂数据整体:(如结构体)其最大的数据成员的长度N;偏移量offset须满足:offset%N = 0

- 指定对齐参数:

预编译指令 #pragma pack(…)

1) 作用:指定结构体、联合以及类成员的 packing alignment;(默认的对齐参数)

2) 语法:#pragma pack( [show] , [push | pop] , [ identifier] , n )

3) 说明:pack 提供数据声明级别的控制,对定义不起作用;调用pack时不指定参数,n将被设成默认值;

4) 具体分析:

1、show:可选参数;显示当前packing aligment的字节数,以warning message的形式被显示;

2、push:可选参数;将当前指定的packing alignment数值进行压栈操作,这里的栈是the internal compiler stack,同时设置当前的packing alignment为n;如果n没有指定,则将当前的packing alignment数值压栈;

3、pop:可选参数;从internal compiler stack中删除最顶端的record;如果没有指定n,则当前栈顶record即为新的packing alignment数值;如果指定了n,则n将成为新的packing aligment数值;如果指定了identifier,则internal compiler stack中的record都将被pop直到identifier被找到,然后pop出identitier,同时设置packing alignment数值为当前栈顶的record;如果指定的identifier并不存在于internal compiler stack,则pop操作被忽略;

4、identifier:可选参数;同push一起使用时,赋予当前被压入栈中的record一个名称;当同pop一起使用时,从internal compiler stack中pop出所有的record直到identifier被pop出,如果identifier没有被找到,则忽略pop操作;

5、n:可选参数;指定packing的数值,以字节为单位;缺省数值是8,合法的数值分别是1、2、4、8、16。

默认情况

win32下默认的对齐参数为8,win64下默认的对齐参数为16(即 double 所占字节数)

所以当没有特别指定对齐参数的时候,按自身对齐参数来对齐数据:

1)编译器在为结构体变量开辟空间时,首先找到结构体中最宽的数据类型,然后寻找内存地址能被该数据类型大小整除的位置,这个位置作为结构体变量的首地址。所以将最宽数据类型的大小作为对齐参数。

2)结构体每个成员相对结构体首地址的偏移量(offset)必须是对齐参数的整数倍(offset%N = 0),如有需要会在成员之间填充字节。也可能会在最后一个成员末尾填充若干字节使得所占空间大小是最宽数据类型大小的整数倍。

栗子

下面看一下sizeof在计算结构体大小的时候具体是怎样计算的

1.test1   空结构体
typedef struct node
{

}S;

sizeof(S)=1  或  sizeof(S)=0   //在C++中占1字节,而在C中占0字节。

2.test2
typedef struct node1
{
    int a;
    char b;
    short c;
}S1;

sizeof(S1)=8   //因为结构体node1中最长的数据类型是int,占4个字节,因此以4字节对齐,则存储方式为:

|--------int--------|   4字节

|char|----|--short-|   4字节

3.test3
typedef struct node2
{
    char a;
    int b;
    short c;
}S2;

siezof(S3)=12   //最长数据类型为int,占4个字节。因此以4字节对齐,则存储方式为:

|char|----|----|----|  4字节

|--------int--------|  4字节

|--short--|----|----|  4字节

4.test4  含有静态数据成员
typedef struct node3
{
    int a;
    short b;
    static int c;
}S3;

sizeof(S3)=8   //这里结构体中包含静态数据成员,而静态数据成员的存放位置与结构体实例的存储地址无关(注意只有在C++中结构体中才能含有静态数据成员,而C中结构体中是不允许含有静态数据成员的)。则存储方式为:

|--------int--------|   4字节

|--short-|----|----|    4字节

而变量c是单独存放在静态数据区的,因此用siezof计算其大小时没有将c所占的空间计算进来。

5.test5  结构体中含有结构体
typedef struct node4
{
    bool a;
    S1 s1;
    short b;
}S4;

sizeof(S4)=16 //s1占8字节,而s1中最长数据类型为int,占4个字节,bool类型1个字节,short占2字节,因此以4字节对齐,则存储方式为:

|-------bool--------|  4字节

|-------s1----------|  8字节

|-------short-------|  4字节

6.test6
typedef struct node5
{
    bool a;
    S1 s1;
    double b;
    int c;
}S5;

sizeof(S5)=32   //s1占8个字节,而s1中最长数据类型为int,占4个字节,而double占8个字节,因此以8字节对齐,则存放方式为:

|--------bool--------|    8字节

|---------s1---------|    8字节

|--------double------|    8字节

|----int----|---------|     8字节

7.test7

若在程序中使用了 #pragma pack(n) 强制以n字节对齐时,默认情况下n为8.

则比较n和结构体中最长数据类型所占的字节大小,取两者中小的一个作为对齐标准。

若需取消强制对齐方式,则可用命令#pragma pack(),即恢复到默认

如果在程序开头使用命令#pragma pack(4),对于下面的结构体

typedef struct node5
{
    bool a;
    S1 s1;
    double b;
    int c;
}S5;

sizeof(S5)=24   //强制以4字节对齐,而S5中最长数据类型为double,占8字节,因此以4字节对齐。在内存中存放方式为:

|-----------a--------|   4字节

|--------s1----------|   4字节

|--------s1----------|   4字节

|--------b-----------|   4字节

|--------b-----------|   4字节

|---------c----------|    4字节

总结

总结一下,在计算sizeof时主要注意一下几点:

1)若为空结构体,则只占1个字节的单元

2)若结构体中所有数据类型都相同,则其所占空间为 成员数据类型长度×成员个数

若结构体中数据类型不同,则取最长数据类型成员所占的空间为对齐标准,数据成员包含另一个结构体变量t的话,则取t中最 长数据类型与其他数据成员比较,取最长的作为对齐标准,但是t存放时看做一个单位存放,只需看其他成员即可。

3)若使用了#pragma pack(n)命令强制对齐标准,则取n和结构体中最长数据类型占的字节数两者之中的小者作为对齐标准。

另外除了结构体中存在对齐之外,普通的变量存储也存在字节对齐的情况,即自身对齐。编译器规定:普通变量的存储首地址必须能被该变量的数据类型宽度整除。

时间: 2024-09-29 08:40:13

结构体 字节对齐的相关文章

结构体字节对齐

结构体字节对齐 在用sizeof运算符求算某结构体所占空间时,并不是简单地将结构体中所有元素各自占的空间相加,这里涉及到内存字节对齐的问题.从理论上讲,对于任何 变量的访问都可以从任何地址开始访问,但是事实上不是如此,实际上访问特定类型的变量只能在特定的地址访问,这就需要各个变量在空间上按一定的规则排列, 而不是简单地顺序排列,这就是内存对齐. 内存对齐的原因: 1)某些平台只能在特定的地址处访问特定类型的数据: 2)提高存取数据的速度.比如有的平台每次都是从偶地址处读取数据,对于一个int型的

结构体字节对齐问题(转)

原文出处:http://wenku.baidu.com/view/019e26b765ce0508763213e2.html 初学C,对结构体的使用sizeof计算所占字节数不是很明白,看了此篇文章,终于豁然开朗,转载过来,方便以后温故. #include<stdio.h> struct a {   char no[10];   int p;   long int pp;   unsigned int ppp;   char x;   float y;   double h; }xy; voi

C++结构体字节对齐

本站文章均为Jensen抹茶喵原创,转载务必在明显处注明:转载自[博客园] 原文链接:http://www.cnblogs.com/JensenCat/p/4770171.html 直接上源码吧!~ 这里是头文件结构的定义: 一个非字节对齐结构体_tagTest2 一个字节对齐_tagTest3 (使用#pragma pack(push,1)来使字节以1个来对齐 , 使用#pragma pack(pop)来还原默认) 1 #pragma once 2 3 4 struct _tagTest1 5

关于结构体字节对齐的笔记

1,空结构体的字节大小为:1: 2,含有static成员的结构体:sizeof 只算存栈中分配的空间大小,static成员存储在全局数据区内,故 static 成员变量不计算在内. 3,在默认对齐方式中,每种类型的存储开始地址是 能被该类型大小整除的地址.故:每次计算都假设结构体开始地址是 0: 4,遇到成员是结构体变量的:将此结构体变量当做一个数据类型,但是: 注意: 千万不能把此结构体的 sizeof 当做该变量的类型大小 也不能直接将此结构体拆解开 解法: 此结构体成员变量的类型大小 理解

C#.NET结构体字节对齐[转载]

[StructLayout(LayoutKind.Sequential,   CharSet=CharSet.Ansi)]     internal   struct   DllInvoices     {     [MarshalAs(UnmanagedType.ByValArray,   SizeConst=8)]     public   byte[]   serial;     public   byte   Type;     public   uint   Sum;     }   

零基础入门之结构体字节对齐

一.字节对齐的规则: 1.一般设置的对齐方式为1,2,4字节对齐方式.结构的首地址必须是结构内最宽类型的整数倍地址:另外,结构体的每一个成员起始地址必须是自身类型大小的整数倍(需要特别注意的是windows下是这样的,但在linux的gcc编译器下最高为4字节对齐),否则在前一类型后补0:这里特别提到的是数组一定要注意,而且在一些编程的技巧中,我们可以使用数组强制字节达到对齐的目的.这在网络编程中是很常见的. 举例:比如CHAR型占用空间为1字节,则其起始位置必须可被1整除.INT为4字节,其起

结构体边界对齐

结构体边界对其是一个老生常谈的话题了,网上的解释非常多,但大多偏重于讲步骤,对于每一步的原因都有点不清楚的地方,下面结合网上的讲解和自己的理解谈谈结构体对齐,不一定正确. 1.什么是结构体对齐. struct A{ char  a: char b: int c: char  d: } 对于上面的这个结构体,假设机器字长32位(4字节),那么该结构体变量占用的空间并非1+1+4+1=7,而是1+3+4+1+3=12.编译器自动将c的起始位置调整到第4个字节处,并在结构体最后加了3个字节,这种编译器

C语言 结构体(联合体)对齐规则

/* 结构体(联合体)对齐规则 */ #include <stdio.h> #include <stdlib.h> #include <string.h> /* * 原则1.第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储). * 原则2.结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最宽基本类型大小的整数倍地址开始存储. *原则3.结构

c语言的结构体字节数统计

struct结构体的字节数 等于 结构体中最大类型的字节数的倍数. 如:?typedef struct Student{??? short id; //2个字节??? char name[15]; //1*15个字节??? int age; //4个字节??? char num; //1个字节} Student; 总共28个字节. c语言的结构体字节数统计