C语言字节对齐规则总结
原始链接源自 https://www.cnblogs.com/clover-toeic/p/3853132.html , 从上面博客中学习总结得到下面的文章。
不同硬件平台,对存储空间的处理不一样,比如不能放奇数地址,不能任意存放等,为了适应不同的架构,在C语言层面上,就可以执行对齐从而独立于硬件平台。 此外,是由于对内存的存取效率问题,如果存放的地址不对齐,取一个4字节的数据,可能会需要两个时钟信号才能取完。为了CPU能够对数据进行快速的访问,也要求数据的起始地址具有对齐特性。 比如4字节数据的起始地址应该在4字节的边界上,也就是数据存放的起始地址应该被4整除。这就是为什么要字节对齐, 和什么是字节对齐。
对齐的方式,又区分 结构体对齐、 栈内存对齐、位域对齐, 位域本质上是结构体。
对于Intel X86平台,每次分配内存应该是从4的整数倍地址开始分配,无论是对结构体变量还是简单类型的变量。
一、结构体对齐
编译器为结构体的每个成员按照其自然边界(alignment)分配空间。各成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。
对齐规则:
1) 数据类型自身的对齐值:char型数据自身对齐值为1字节,short型数据为2字节,int/float型为4字节,double型为8字节。
2) 结构体的自身对齐值:其成员中自身对齐值最大的那个值。
3) 指定对齐值:#pragma pack (value)时的指定对齐值value。默认是4。
4) 数据成员、结构体的有效对齐值:自身对齐值和指定对齐值中较小者,即有效对齐值=min{自身对齐值,当前指定的pack值}。
使用pragma指定对齐值,其实是指定了数据结构的最大对齐值, 如果本身的对齐值,并不超过设定的值,还是会按照自身的对齐值来。
有效对齐值N是最终用来决定数据存放地址方式的值。有效对齐N表示“对齐在N上”,即该数据的“存放起始地址%N=0”。结构体的成员变量要对齐存放,结构体本身也要根据自身的有效对齐值圆整(即结构体成员变量占用总长度为结构体有效对齐值的整数倍)。
struct A{int a;char b;short c;
};
struct B{char b;int a;short c;
};
sizeof(A) = 8, sizeof(B) = 12;
A中,最初的int是4字节对齐,char是1字节对齐,所以前5个字节不需要填充,后面short长度为2个字节,和2对齐,所以char后面补一个字节,总共是8个字节。整个数组的有效对齐值是成员的最大值4, 8个字节是4的整数倍, 所以结构体总长度为8。
B中,最初char是1字节,随后int长度是4字节,和4字节对齐,char后面补3个字节,最后short是第9和10字节,也是对齐的。整个结构体的有效对齐值是4,结构体长度需要是4的整数倍,所以short后面还需要补2个字节,总长度为12。
之所以编译器在后面补充2个字节,是为了实现结构数组的存取效率。试想如果定义一个结构B的数组,那么第一个结构起始地址是0没有问题,但是第二个结构呢?按照数组的定义,数组中所有元素都紧挨着。如果我们不把结构体大小补充为4的整数倍,那么下一个结构的起始地址将是0x0000A,这显然不能满足结构的地址对齐。因此要把结构体补充成有效对齐大小的整数倍。
更改对齐方式:
在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间。一般地,可以通过下面的方法来改变缺省的对界条件:
使用伪指令#pragma pack(n):C编译器将按照n个字节对齐;
使用伪指令#pragma pack(): 取消自定义字节对齐方式。
在编码时,可用#pragma pack动态修改对齐值。自定义对齐值后要用#pragma pack()来还原,否则会对后面的结构造成影响。
#pragma pack(2) //指定按2字节对齐
struct C{char b;int a;short c;
};
#pragma pack() //取消指定对齐,恢复缺省对齐
char自身对齐值是1,指定对齐值是2,所以有效对齐值是1。 int自身对齐值是4,指定对齐值是2,所有有效对齐值是2,放在2的倍数的地址空间上,char后面只会补1个字节。所以到这里长度是6,后面short两个字节,有效对齐值也是2,结构体总长度是8。
需要注意,pragma pack指定的对齐值,是数据类型的最大对齐值,可以小,但是不能大。
因为对齐,会产生的问题:
1,数据类型强转可能会因为对齐,出错。 short类型应该放在2的倍数的地址上,但是这里p1却指向了奇数地址。需要注意。
int main(void){ unsigned int i = 0x12345678;unsigned char *p = (unsigned char *)&i;*p = 0x00;unsigned short *p1 = (unsigned short *)(p+1);*p1 = 0x0000;return 0;
}
2,不同的处理器之间传递数据时,因为两个处理器可能采用的填充方式不一致,会导致数据出错。这时,可以在定义数据结构时,自己把需要填充的部分用char类型的数据填上,这样就不会不一致了。或者使用pragma pack 1, 让数据都按照1字节对齐。
二、栈内存对齐
在VC/C++中,栈的对齐方式不受结构体成员对齐选项的影响。总是保持对齐且对齐在4字节边界上。(直接看博客原文吧,他里面说的char和short没有凑到4个字节,我认为是已经凑到一起了)。
三、位域的对齐方式
有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1两种状态,用一位二进位即可。为了节省存储空间和处理简便,C语言提供了一种数据结构,称为“位域”或“位段”。
1,为了节省内存,对于大量的结构体数组来讲。 2,需要访问字节内的bit成员。两种情况会使用位域。
位域成员,除了指定所占用的bit位外,还有一个类型。位域成员不能单独被取sizeof值。下面主要讨论含有位域的结构体的sizeof。
其对齐规则大致为:
1) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++和GCC采取压缩方式;
4) 如果位域字段之间穿插着非位域字段,则不进行压缩;
5) 整个结构体的总大小为最宽基本类型成员大小的整数倍,而位域则按照其最宽类型字节数对齐。
位域可以无位域名,只用作填充或调整位置,占位大小取决于该类型。例如,char :0表示整个位域向后推一个字节,即该无名位域后的下一个位域从下一个字节开始存放,同理short :0和int :0分别表示整个位域向后推两个和四个字节。
当空位域的长度为具体数值N时(如int :2),该变量仅用来占位N位。
原文还有位域的例子和字节大小端的例子,在这里就不写了。
C语言字节对齐规则总结相关推荐
- C语言结构体字节对齐规则
C语言结构体字节对齐规则 基本规则 规则1 :结构体(struct)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存放在offset为该数据成员大小的整数倍的地方(比如int在 ...
- 程序人生 | C语言字节对齐问题详解 - 对齐/字节序/位序/网络序等(上)
本文首发于 2014-07-21 15:32:28 1. 引言 考虑下面的结构体定义: typedef struct{char c1;short s; char c2; int i; }T_FOO; ...
- C语言字节对齐问题详解
转载原文连接:https://www.cnblogs.com/clover-toeic/p/3853132.html C语言字节对齐问题详解 引言 考虑下面的结构体定义: 1 typedef stru ...
- 结构体对齐(字节对齐)规则及大小计算
什么是字节对齐 这跟读取数据有关,cpu读取一次能读取到的内存大小跟数据总线的位数有关,如果数据总线为16位,那么cpu一次能够读取2字节:如果为32位那么cpu一次可以读取4字节,而读取数据是需要消 ...
- c语言强制4字节对齐,C语言字节对齐4
非字节对齐类型的字节对齐规则 我们可以使用"__packed"."__attribute__((packed))"."#pragma"等方式 ...
- (转)C语言字节对齐
图片可以在下面的博客中看到. 转自:http://blog.csdn.net/bigloomy/article/details/6633008 可能有不少读者会问,字节对齐有必要拿出来单独写一篇博客嘛 ...
- c如何通过偏移量取出文件中的字节_理一理C语言字节对齐的那些事
作者:守望,Linux应用开发者,目前在公众号[编程珠玑] 分享Linux/C/C++/数据结构与算法/工具等原创技术文章和学习资源. 前言 字节对齐是我们初学C语言就会接触到的一个概念,但是到底什么 ...
- c语言4字节对齐,理一理C语言字节对齐的那些事
前言 字节对齐是我们初学 C语言 就会接触到的一个概念,但是到底什么是字节对齐?对齐准则又是什么?为什么要字节对齐呢?字节对齐对我们编程有什么启示?本文将简单理一理字节对齐的那些事. 什么是字节对齐 ...
- C语言字节对齐问题详解(zz)
http://www.bubuko.com/infodetail-263205.html 引言 考虑下面的结构体定义: typedef struct{char c1;short s; char c2; ...
最新文章
- @async 默认线程池_.NET Web应用中为什么要使用async/await异步编程?
- ISE include 头文件错误的解决办法
- 自用零散博文-route_state.ts
- 15.枚举enum.rs
- zigbee板子:lcd显示汉字
- 为什么 MapReduce 再次流行起来了?
- *与**在python中的使用
- css3媒体查询尺寸
- 小程序:微信小程序开发
- Linux_I2C读写流程
- CCNA题库第一部分
- c语言:输出一个菱形图案
- Python爬虫——糗百
- 金山wps支持java接口开发吗_金山wps开放平台使用踩坑实录
- MBR10100FCT-ASEMI肖特基二极管MBR10100FCT
- Ninth season twenty-first episode,Chandler and Monica may never have children??????
- SQL开窗函数(窗口函数)详解
- Qt帮助文档无法打开的解决方案
- Ping不通的原因分析
- 利用菜单配置文件生成菜单