字节顺序是指占内存多于一个字节类型的数据在内存中的存放顺序,通常有小端、大端两种字节顺序。小端字节指低字节数据存放在内存低地址处,高字节数据存放在内存的高地址处;大端字节序是高字节数据存放在低地址处,低字节数据存放在高地址处。基于X86平台的PC机是小端字节序的,而有的嵌入式平台则是大端字节序的。因而对int、uint16、uint32等多于1字节类型的数据,在这些嵌入式平台上应该变换其存储顺序。通常我们认为,在网络中传输的字节的顺序即网络字节序为标准顺序,考虑到与协议的一致以及与同类其他平台产品的互通,在程序中发数据包时,将主机字节序转换为网络字节序,收数据包处将网络字节序转换为主机字节序。
对于下面的结构体:
- struct test
- {
- char x1;
- short x2;
- float x3;
- char x4;
- };
结构各成员空间分配情况是怎么样的?
文章中解释:
结构的第一个成员x1,其偏移地址为0,占据了第1个字节。第二个成员x2为short类型,其起始地址必须2字节对界,因此,编译器在x2和x1之间填充了空字节。结构的第三个成员x3和第四个成员x4恰好落在了其自然对界地址上,在它们前面不需要额外的填充字节。在test结构体中,成员x3要求4字节对齐,是该结构所有成员中要求的最大对界单元,因而test结构的自然对界条件为4字节,编译器在成员x4后面填充了 3个空字节。整个结构所占据空间为12字节。
同时,说明了更改C编译器的缺省字节对齐方式:在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间。一般地,可以通过下面的方法来改变缺省的对界条件:
· 使用伪指令#pragma pack (n),C编译器将按照n个字节对齐。
· 使用伪指令#pragma pack (),取消自定义字节对齐方式。
另外,还有如下的一种方式:
· __attribute((aligned (n))),让所作用的结构成员对齐在n字节自然边界上。如果结构中有成员的长度大于n,则按照最大成员的长度来对齐。
· __attribute__ ((packed)),取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐。
以上的n = 1, 2, 4, 8, 16... 第一种方式较为常见。
下面是CSDN上提出的问题(原文<<intel和微软和本公司同时出现的面试题>>:http://community.csdn.net/Expert/TopicView3.asp?id=3804035)
- #pragma pack(8)
- struct s1
- {
- short a;
- long b;
- };
- struct s2
- {
- char c;
- s1 d;
- long long e;
- };
- #pragma pack()
问:
(1)sizeof(s2) = ?
(2)s2的c后面空了几个字节接着是d?
下面是redleaves给出解释:
很详尽,很透彻,从论坛原文后头的对话可以看出redleaves对C/C++的标准理解很深刻,值得学习:
- #pragma pack(8)
- struct S1
- {
- char a;
- long b;
- };
- struct S2 {
- char c;
- struct S1 d;
- long long e;
- };
- #pragma pack()
sizeof(s2)结果为24。
成员对齐有一个重要的条件,即每个成员分别对齐,即每个成员按自己的方式对齐。
也就是说上面虽然指定了按8字节对齐,但并不是所有的成员都是以8字节对齐。其对齐的规则是:每个成员按其类型的对齐参数(通常是这个类型的大小)和指定对
齐参数(这里是8字节)中较小的一个对齐。并且结构的长度必须为所用过的所有对齐参数的整数倍,不够就补空字节。
s1中,成员a是1字节,默认按1字节对齐,指定对齐参数为8,这两个值中取1,a按1字节对齐;成员b是4个字节,默认是按4个字节对齐,这时就按4个字节对齐。所以sizeof(s1) = 8。
s2中,c和s1中的a一样,按1字节对齐,而d是个结构,它是8个字节,它按什么对齐呢?对于结构来说,它的默认对齐方式就是它的所有成员使用的对齐参数中最大的一个,s1的就是4。所以,成员d就是按4字节对齐,成员e是8个字节对齐,它是默认按8个字节对齐,和指定的一样,所以它对到8字节的边界。这时,已经使用了12个字节了,所以又添了4个字节的空,从第16个字节开始放置成员e。这是,长度为24,已经可以按8(成员e按8字节对齐)整除。这样,一共使用了24个字节。
a b
s1的内存布局:11**,1111,
c s1.a s1.b d
s2的内存布局:1***,11**,1111,****11111111
这里有三点很重要:
(1)每个成员分别按自己的方式对齐,并能最小化长度;
(2)复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,这样在成员是复杂类型时,可以最小化长度;
(3)对齐后的长度必须是成员中最大的对齐参数的整数倍,这样在处理数组时可以保证每一项都边界对齐;
对于数组,比如:
char a[3];这种,它的对齐方式和分别写3个char是一样的.也就是说它还是按1个字节对齐。
如果写:typedef char Array3[3];
Array3这种类型的对齐方式还是按1个字节对齐,而不是按它的长度。
不论类型是什么,对齐的边界一定是1,2,4,8,16,32,64....中的一个。
下面是从另外一篇文章(http://community.csdn.net/Expert/TopicView3.asp?id=3564500)的一些对各个类型以及结构体对齐方式的补充:
为了能使CPU对变量进行高效快速的访问,变量的起始地址应该具有某些特性,即所谓的”对齐“。例如对于4字节的int类型变量,其起始地址应该位于4字节边界上,即起始地址能够被4整除。变量的对齐规则如下(32位系统):
Type
Alignment
char
在字节边界上对齐
short (16-bit)
在双字节边界上对齐
int and long (32-bit)
在4字节边界上对齐
float
在4字节边界上对齐
double
在8字节边界上对齐
structures
单独考虑结构体的每个成员,它们在不同的字节边界上对齐。
其中最大的字节边界数就是该结构的字节边界数。
如果结构体中有结构体,那么这是一个递归的过程。
设编译器设定的最大对齐字节边界数为n,对于结构体中的某一成员item,它相对于结构首地址的实际字节对齐数目x应该满足以下规则:
x = min(n, sizeof(item)
例如,对于结构体:
- struct
- {
- char a;
- long b;
- }T;
当位于32位系统,n = 8时:
a的偏移量为0,b的偏移量为4,中间填充了3个字节,b的x为4。
当位于32位系统,n = 2时:
a的偏移量为0,b的偏移为2,中间填充了1个字节,b的x为2。
结构体的sizeof:
设结构体的最后一个成员为LastItem,其相对于结构体首地址的偏移为offset(LastItem),其大小为sizeof(LastItem),结构体的字节对齐数为N,则:结构体的sizeof 为: 若offset(LastItem)+ sizeof(LastItem)能够被N整除,那么就是offset(LastItem)+ sizeof(LastItem),否则,在后面填充,直到能够被N整除。
另外:
1) 对于空结构体,sizeof == 1;因为必须保证结构体的每一个实例在内存中都有独一无二的地址.
2)结构体的静态成员不对结构体的大小产生影响,因为静态变量的存储位置与结构体的实例地址无关。例如:
struct {static int I;} T;
struct {char a; static int I;} T1;
sizeof(T) == 1; sizeof(T1) == 1;
引用:blog.csdn.net/xuegao007/article/details/1708360