结构体怎么对齐?
- 结构体对齐规则:
-
第一个成员在结构体地址偏移量为0的地址处
-
其余成员变量要在某个数字的整数倍处(对齐数)的地址
注意:对齐数为编译器默认的数值与该成员中较小的值
vs下默认的对齐数是8 gcc下默认的对齐数是4 -
结构体总大小为:最大对齐数(所有变量的最大者与编译器默认的对齐参数取最小)的整数倍
-
如果有嵌套结构体的情况,嵌套的结构体的对齐到自己最大对齐数的整数倍处,结构体的整体大小就是结构体中最大对齐数的整数倍
-
那么为什么要有内存对齐?
- 平台原因(移植原因):不是所有的平台都支持访问任意地址的任意数据的,某些硬件只能处理某些特定类型的数据,否则会抛出硬件异常
- 性能原因:数据结构(尤其是栈)应尽量向自然边界对齐,原因是处理器要想访问未对齐的数据需要操作两次内存访问,而对于对齐的数据只需一次内存访问就可以获取到
总体来说:内存对齐是空间换时间的做法
如何让结构体进行指定参数的对齐?
- #pragma 这个预处理指令可以改变默认的对齐参数
#pragma pack() 还原默认的对齐数 ,#pragma pack(1)设置为8
#pragma pack(8)设置为8,#pragma pack(4)设置为4
#pragma pack()
struct
{
结构体成员变量/函数
}
#pragma pack()
//默认对齐数不一定是最终的对齐数,这要遵循结构体对齐规则
如何知道结构体成员中某个结构体成员相对结构体起始位置的偏移量
- offsetof宏的实现可用来解决 (在不知结构体成员位于那些成员之后和不知结构体地址的情况)
#include<stdio.h>
#include<stddef.h>
#include<stdlib.h>
struct student
{
int a;
char b;
double c;
}student;
int main()
{
printf("student b is %d\n", (int)offsetof(struct student, b));
system("pause");
return 0;
}
什么是大小端?
- 大端(Big-Endian):数据的低字节保存在内存的高地址中,高字节保存在内存的低地址中
- 小段(Little-Endian):数据的低字节保存在内存的低地址中,高字节保存在内存的高地址中
- 为什么要有大小端?
- 因为在计算机系统中是以字节为单位的,每个地址单元对应一个字节,但在c语言中,除了char是一个字节外,其余的像short是两个字节的,int是4个字节的,long在32位系统是4个字节,64位系统下是8个字节,double在32位系统下为8个字节,在64位系统下为16个字节,由于寄存器的宽度大于一个字节,因此在存储时必然就存在如何存储的问题,也就产生了大小端的存储方式
大小端的优势对比:
大端:顺序存储,符合人们阅读的习惯,符号位保存在第一个字节中,便于判断数据正负
小端:1.因为小端是由低地址存放低位,因此在强制类型转换上不用调节字节内容。2.CPU在做数值运算的时候,是由低位到高位读取数据运算,直到刷新到最到位,这样的话在运算方式会更高效
- 因为在计算机系统中是以字节为单位的,每个地址单元对应一个字节,但在c语言中,除了char是一个字节外,其余的像short是两个字节的,int是4个字节的,long在32位系统是4个字节,64位系统下是8个字节,double在32位系统下为8个字节,在64位系统下为16个字节,由于寄存器的宽度大于一个字节,因此在存储时必然就存在如何存储的问题,也就产生了大小端的存储方式
如何测试某台机器是大端还是小端?
- 使用强制转换操作判断
- int i = 1,使i强制转换类型为char的指针再进行解引用,如果&1结果为1则为小端,否则为大端
#include<iostream>
using namespace std;
int main()
{
int i = 1;
if (*(char *)&i == 1)
{
cout << "小端模式" << endl;
}
else{
cout << "大端模式" << endl;
}
return 0;
}
VS下运行结果
- 使用联合体
- 创建联合体{int i ;char j} ,给i赋值1;打印b的数值;如果为1则是小端,否则为大端
#include<iostream>
using namespace std;
union
{
int i;
char b;
}un;
int main()
{
un.i = 1;
if (un.b == 1)
{
cout << "小端模式" << endl;
}
else{
cout << "大端模式" << endl;
}
return 0;
}
VS下运行结果
大小端的应用场景是什么?
- Intel的80×86系列芯片使用小端存储模式
ARM芯片默认采用小端,但可以切换为大端
MIPS芯片采用大端,但可以在大小端之间切换
在网络上传输的数据普遍采用的都是大端