博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
typedef __packed struct (结构体字节对齐)(转)
阅读量:4112 次
发布时间:2019-05-25

本文共 3528 字,大约阅读时间需要 11 分钟。

结构体字节对齐

在用sizeof运算符求算某结构体所占空间时,并不是简单地将结构体中所有元素各自占的空间相加,这里涉及到内存字节对齐的问题。从理论上讲,对于任何 变量的访问都可以从任何地址开始访问,但是事实上不是如此,实际上访问特定类型的变量只能在特定的地址访问,这就需要各个变量在空间上按一定的规则排列, 而不是简单地顺序排列,这就是内存对齐。  内存对齐的原因:  1)某些平台只能在特定的地址处访问特定类型的数据;  2)提高存取数据的速度。比如有的平台每次都是从偶地址处读取数据,对于一个int型的变量,若从偶地址单元处存放,则只需一个读取周期即可读取该变量;但是若从奇地址单元处存放,则需要2个读取周期读取该变量。   win32平台下的微软C编译器对齐策略:  1)结构体变量的首地址能够被其最宽数据类型成员的大小整除。编译器在为结构体变量开辟空间时,首先找到结构体中最宽的数据类型,然后寻找内存地址能被该数据类型大小整除的位置,这个位置作为结构体变量的首地址。而将最宽数据类型的大小作为对齐标准。  2)结构体每个成员相对结构体首地址的偏移量(offset)都是每个成员本身大小的整数倍,如有需要会在成员之间填充字节。编译器在为结构体成员开辟空 间时,首先检查预开辟空间的地址相对于结构体首地址的偏移量是否为该成员大小的整数倍,若是,则存放该成员;若不是,则填充若干字节,以达到整数倍的要 求。  3)结构体变量所占空间的大小必定是最宽数据类型大小的整数倍。如有需要会在最后一个成员末尾填充若干字节使得所占空间大小是最宽数据类型大小的整数倍。

下面看一下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字节

总共占8字节

3.test3

typedef struct node2

{
char a;
int b;
short c;
}S2;
则siezof(S3)=12.最长数据类型为int,占4个字节。因此以4字节对齐,其在内存空间存放方式如下:

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

|——–int——–| 4字节

|–short–|—-|—-| 4字节

总共占12个字节

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和结构体中最长数据类型占的字节数两者之中的小者作为对齐标准。

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

测试程序:

?

/测试sizeof运算符 2011.10.1/

include

using namespace std;

//#pragma pack(4) //设置4字节对齐
//#pragma pack() //取消4字节对齐

typedef struct node

{

}S;

typedef struct node1

{
int a;
char b;
short c;
}S1;

typedef struct node2

{
char a;
int b;
short c;
}S2;

typedef struct node3

{
int a;
short b;
static int c;
}S3;

typedef struct node4

{
bool a;
S1 s1;
short b;
}S4;

typedef struct node5

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

int main(int argc, char *argv[])

{
cout<

pragma pack (2) /指定按2字节对齐/

struct C

{
char b;
int a;
short c;
};

pragma pack () /取消指定对齐,恢复缺省对齐/sizeof(struct C)值是8。

修改对齐值为1:

pragma pack (1) /指定按1字节对齐/

struct D

{
char b;
int a;
short c;
};

pragma pack () /取消指定对齐,恢复缺省对齐/

sizeof(struct D)值为7。ARM下的对齐处理,可以使用 __packed,(_packed有可能是编译器关键字 )

typedef struct

{
char x;
int y;
}struct1;

typedef __packed struct

{
char x;
int y;
}struct2;在32位的ARM SDT编译器中
sizeof(struct1)值为8
sizeof(struct2)值为5;

__packed是进行一字节对齐。使用_packed一般会以降低运行性能为代价,由于大多数cpu处理数据在合适的字节边界数的情况下会更有效,packed的使用会破坏这种自然的边界数。

转载地址:http://iyrsi.baihongyu.com/

你可能感兴趣的文章
HTTP和HttpServletRequest 要点
查看>>
在osg场景中使用GLSL语言——一个例子
查看>>
关于无线PCB中 中50欧姆的特性阻抗的注意事项
查看>>
Spring的单例模式源码小窥
查看>>
后台服务的变慢排查思路(轻量级应用服务器中测试)
查看>>
MySQL中InnoDB事务的默认隔离级别测试
查看>>
微服务的注册与发现
查看>>
bash: service: command not found
查看>>
linux Crontab 使用 --定时任务
查看>>
shell编程----目录操作(文件夹)
查看>>
机器学习-----K近邻算法
查看>>
HBASE安装和简单测试
查看>>
关于程序员的59条搞笑但却真实无比的编程语录
查看>>
tomcat 使用心得(问题)-eclipse 启动tomcat 后 浏览器访问404 --eclipse复制工程显示原来的工程名
查看>>
搞笑--一篇有趣的文章编译自一篇西班牙博客。有一位美丽的公主,被关押在一个城堡中最高的塔上,一条凶恶的巨龙看守着她,需要有一位勇士营救她…
查看>>
非常不错 Hadoop 的HDFS (Hadoop集群(第8期)_HDFS初探之旅)
查看>>
Tomcat启动错误,端口占用
查看>>
安卓模拟器请求本地资源,不修改hosts
查看>>
laravel 修改api返回默认的异常处理
查看>>
高德坐标转换百度坐标 javascript
查看>>