文案类的网站,wordpress 分词标签,大连建设教育网站,网络推广软件全邀zjkwlgs一#xff1a;字节对齐的概念 针对字节对齐#xff0c;百度百科的解释如下#xff1a; 字节对齐是字节按照一定规则在空间上排列#xff0c;字节(Byte)是计算机信息技术用于计量存储容量和传输容量的一种计量单位#xff0c;一个字节等于8位二进制数#xff0c;在UTF-8编…一字节对齐的概念 针对字节对齐百度百科的解释如下 字节对齐是字节按照一定规则在空间上排列字节(Byte)是计算机信息技术用于计量存储容量和传输容量的一种计量单位一个字节等于8位二进制数在UTF-8编码中一个英文字符等于一个字节字节按照一定规则在空间上排列就是字节对齐。 上面就提到按照一定规则那规则是什么按什么规则去对齐带着这个疑问往下走
二为什么要字节对齐 我们为什么要进行字节对齐不对齐会有什么后果在计算机中我们任何一个动作无非就是保证程序的正确性提高程序的性能和可靠性。 1平台的硬要求必须要字节对齐 某些平台对特定类型的数据只能从特定地址开始存取而不允许其在内存中任意存放。例如Motorola 68000 处理器不允许16位的字存放在奇地址否则会触发异常因此在这种架构下编程必须保证字节对齐。 2提高程序的性能 字节对齐如何能提高程序的性能CPU内部有几个重要的部件决定了CPU一次能处理的字节和可访问的内存大小。寄存器ALU和数据总线的位数这些共同决定了CPU的字长常见CPU的字长有4位8位16位32位和64位。字长越多则CPU内部硬件规模和造价越高。如果CPU字长是16位。它的寄存器和总线也是16位。那么它一次处理的数据长度就为2字节。 当访问一个变量时当该变量的地址为偶地址(即字变量的低字节在偶地址单元高字节在奇地址单元)则需要一个总线周期访问该字变量如果该字变量的地址为奇地址(即字变量的低字节在奇地址单元高字节在偶地址单元)则需要用两个连续的总线周期才能访问该字变量每个周期访问一个字节。 字节对齐让CPU读取数据的效果高了这就解释了为什么字节对齐能提高程序的性能。 3节省程序的内存 下面我们以一个实际的例子来看看字节对齐如何节省内存
#include stdio.h
#include stdlib.hstruct byte1
{char a;int b;short c;
};struct byte2
{char a;short c;int b;
};int main()
{// please write your code hereprintf(struct byte1 size:%d\n,sizeof(struct byte1));printf(struct byte2 size:%d\n,sizeof(struct byte2));
} 可以看到同样是存储一个char一个int一个short结构体中顺序不一样结构体的所占的空间也不一样。之所以出现上述结果就是因为编译器要对数据成员在空间上进行对齐
三字节对齐规则
1基本类型对齐规则
基本类型包括char、int、float、double、short、long等基本数据类型。CPU位数不同所占的字节数也不一样如下图所示 对齐要求起始地址为其长度的整数倍即可。如int类型的变量起始地址要求为4的整数倍char类型的变量只占一个字节那起始地址放哪都行。
2结构体对齐规则
1每个数据成员的起始位置必须是自身大小的整数倍
2结构体总大小必须是结构体成员中最大的对齐模数的整数倍
3 结构体包含数组时按单个类型对齐方式
4共用体union取成员的最大内存但包含在结构体内时按union内部最大类型字节数的整数倍开始存储
struct byte1
{char a;int b;short c;
};结构体大小12 解释char占一个字节int占四个字节由于int的起始地址要在4的倍数上char后边补齐3个字节shor占两个字节但是整个结构体大小要是最大的对齐模数的整数倍即4的倍数所以补两个字节一共12个字节
struct byte2
{char a;short c;int b;
};
结构体大小8
解释char占一个字节short占两个字节由于short的起始地址要在2的倍数上char后边补齐1个字节int占四个字节刚好在4的倍数上所以总共8个字节
那结构体里嵌套结构体呢
结构体包含另一个结构体成员则被包含的结构体成员要从其原始结构体内部的最大对齐模数的整数倍地址开始存储比如struct a里含有struct bb中有char、double 、int 元素那么b应该从8double的整数倍开始存储
结构体嵌套共同体
结构体包含共用体成员则该共用体成员要从其原始共用体内部成员中的最大对齐模数的整数倍地址开始存储
结构体最后包含0数组
struct byte2
{char a;short c;int b;double d[0];
}; 结构体最后包含0数组那0数组占空间吗长度为0的数组的主要用途是为了满足需要可变长度的结构体具体用法是在一个结构体的最后申明一个长度为0的数组就可以使得这个结构体是可变长的。对于编译器来说此时长度为0的数组并不占用空间因为数组名本身不占空间它只是一个偏移量数组名这个符号本身代表了一个不可修改的地址常量。
3共同体对齐规则
共同体的内存除了取最大成员内存外还要保证是所有成员类型size的最小公倍数。
union byte3
{char a;short c[5];int b;
}; 共同体byte3中最大成员就是short c[5]占10个字节由于要保证是所有成员类型size的最小公倍数即4个倍数所以是12
4存在#pragma pack宏的对齐规则
#pragma packn//编译器将按照n个字节对齐
#pragma pack//取消自定义字节对齐方式
******对齐规则******
结构体、联合、类的结构成员第一个放在偏移为0的地方以后每个数据成员的对齐按照#pragma pack指定的数值和自身对齐模数中最小的那个。
结构体的大小是#pragma pack指定的数值的整数倍。
#pragma pack(4)
typedef struct
{int age;char name[0];double a;
} Person;
#pragma pack();//结束#pragma pack(4)对齐。 如果没有结束aa也按照#pragma pack(4)对齐typedef struct
{double age;Person k;
} aa;int msizeof(Person); // m12 按照4字节对齐
int nsizeof(aa); // n24, 按照8字节对齐 按照#pragma pack(4)对齐的话n20
5位域字节对齐规则
“位域”是把一个字节中的二进位划分为几个不同的区域并说明每个区域的位数。使用位域的主要目的是压缩存储。
位域列表的形式为 类型说明符 位域名位域长度单位位 bite
如struct bs { int a:8; int b:2; int c:6; } data; 其中位域a占8位位域b占2位位域c占6位。
位域说明
1. 一个位域必须存储在同一个字节中不能跨两个字节。如一个字节所剩空间不够存放另一位域时应从下一单元起存放该位域。
2. 由于位域不允许跨两个字节因此位域的长度不能大于一个字节8位的长度也就是说不能超过8位二进位。 3. 位域可以无位域名这时它只用来作填充或调整位置。无名的位域是不能使用的。例如 int :2
位域对齐规则
1) 如果相邻位域字段的类型相同且其位宽之和小于类型的sizeof大小则后面的字段将紧邻前一个字段存储直到不能容纳为止
2) 如果相邻位域字段的类型相同但其位宽之和大于类型的sizeof大小则后面的字段将从新的存储单元开始其偏移量为其类型大小的整数倍
3) 如果相邻的位域字段的类型不同从新的存储单元开始偏移量为其类型大小的整数倍即不压缩各编译器的具体实现有差异VC6采取不压缩方式Dev- C采取压缩方式
4) 如果位域字段之间穿插着非位域字段则不进行压缩
5) 整个结构体的总大小为最宽基本类型成员大小的整数倍。 例题
1typedef struct AA { unsigned int b1:5; unsigned int b2:5; unsigned int b3:5; unsigned int b4:5; unsigned int b5:5; }AA;
sizeof(AA) 4
【解析】参考规则 1)。由于相邻成员类型相同unsigned int为 4 个字节b1占5位b2加上b1的位数之和为10位不超过4字节因此b2接着b1继续存储 同理b3、b4、b5的类型相同位数之和不超过4字节因此接着b2继续存储总位数为25位。 由于结构体的大小是最宽类型成员的整数倍因此25位之后的补0直到补满4字节。 2typedef struct AA { unsigned int b1:5; unsigned int b2:5; unsigned int b3:5; unsigned int b4:5; unsigned int b5:5; unsigned int b6:5; unsigned int b7:5; }AA; sizeof(AA) 8
【解析】参考规则 1) 和规则 2) 。由于相邻成员类型相同unsigned int为 4 个字节32位当存储到 b7 时b7和b6之前的位数相加超过4字节
因此b7从新的存储单元开始存储。
即b1~b6 存储在 第0~29位第30、31位补0b7从下一个 4字节存储单元 开始存储5位剩下的补0。 3struct test1
{
char a:1;
char :2;
long b:3;
char c:2;
}; sizeof(test1) 12
【解析】
char a1 //用一个字节去存储
char 2 //空域。因为与前面的a的类型相同而两个位域的位宽相加仍然少于8位所以依然用1个字节表示
long b3 //long类型的位宽是4个字节与前面的char类型不同所以b与a之间偏移4个字节它们之间自动补充3个字节
char c2 //因为c与b又不同型以test1中的最长的long类型的位宽进行偏移所以虽然char只用1个字节就够了但依然要占4个字节。
结构体总长以最长的类型位宽做为偏移量最长的是long型占4位所以不同类型之间应该是4个字节的偏移即test1应该是4字节的整数倍。
总共是12字节。