网络字节序的由来:
字节序:cpu在内存中对数据的存取顺序–针对存储大小大于一个字节的数据类型
主机字节序:一个主机的字节序取决于CPU架构,常见的架构—X86(小端字节序)
MIPS大端字节序 只有一个字节以上的才有大小端之分(免费)
小端字节序:低地址存低位
大端字节序:高地址存低位
在网络通信中(两条不同主机之间的通信)-- 通信双方并不知道对方的主机字节序。
主机字节序大小端的识别:
在通信过程中,通信双方有可能因为主机字节序不同而导致数据的二义性(发送的数据和对方获取得到的数据不同)
解决方法:通信时,双方不管自己的主机字节序是什么,在网络通信中的数据全部采用大端字节序格式。(字符串不需要,因为一个字节不分大小端);
网络通信的两端通信:其中一端叫客户端;另一端叫服务端,通信双方中主动发送请求的叫客户端,必须知道服务端在哪里。服务端:服务端必须告诉客户端在哪里(通常的都是一个固定地址)。
主机字节序的判断方法
用联合体可以检测出是大端还是小端,因为联合体共有一块内存
先来复习一下联合体:
联合体是个结构;联合也是一种特殊的自定义类型 这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以 联合也叫共用体)
它的所有成员对于基地址的偏移量都为0;
联合体的结构空间要大到足够容纳最“宽”的成员;且最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍;
所以说大小不一定为里面最长的一个,还和最大对齐数有关。
union{int a=1;uchar b;}
b=1则是小端 b==0 大端
结构体内存对齐
内存对齐特性:
- 第一个成员在与结构体变量偏移量为0的地址处。
- 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处(用默认对齐数与自身相比,取小的值,之后自己应该在该数字的整数倍处)。
3.对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。 VS中默认的值为8 Linux中的默认值为4.
4 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍(所有成员相比 找出最大的对齐数,然后总大小就为它的整数倍)。 - 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是 所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
6.修改默认对齐数:#pragma pack(n) n为要设定的默认对齐数;如果不写那么就恢复默认对齐数
例如如下
struct test1 {
char a; //0 默认对齐数位8 8和1比较 对齐数为1 所以应该在1的整数倍上
int d; //3
char b; //7
int c;//11
double l;//15
};
struct test2 {
char a; //0
int d;//3
char b;//7
int c;//11
double l;//15
struct test1 {
int o;//23 又因为要为最大对齐数的整数倍
};
};
struct test3 {
char a; //1
char d[4];
char b;
int c;
};
struct test3 b;
printf("%d", (char*)&(b.b)-(char*)&b); //该句可以计算出test3中b相对于起始位置的偏移
//当然该语句也可以计算其他
上面的用sizeof求出的大小为24 ,第二个的求出结果为32,test3大小为12,数组的话对齐数取数组里面元素的对齐数比较。
内存对齐原因
1 平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址 处取某些特定类型的数据,否则抛出硬件异常。
2. 性能原因: 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的内存,处理 器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
3.目的也是为了,空间换时间。