C语言字节对齐
C语言结构体字节对齐简单计算方法

C语⾔结构体字节对齐简单计算⽅法
1.在C语⾔⾥⾯每⼀种数据类型都有字节对齐⽐如在32位操作系统下:整型的⾃⾝对齐数就是 4 字节,字符型就是 1 字节,double就是 8 字节。
但是结构体的计算⽅式就和普通的数据类型不⼀样。
在C语⾔⾥⾯字节对齐的⽅式主要根据“有效对齐数”来确定,那么有效对齐数是怎杨确定的呢?
在结构体⾥⾯::: 有效字节对齐数 = (⾃⾝对齐数 < 最⼤字节)?(⾃⾝对齐数):(最⼤字节);
⾃⾝对齐数 = 4字节(32位操作系统);(8 字节为32位操作系统)。
最⼤字节数 = 结构体⾥⾯最⼤的⼀个数据类型所占的字节数。
列:struct test{
char a;
int a;
short c;
}d;
sizeof(d) == ? ; //在32位操作系统下为12字节,64位操作系统下也为12字节。
(每⼀次都开4个字节)
struct test2{
char a;
double b;
short c;
}d;
sizeof(d) == ? ;// 在32位操作系统下为16字节(每⼀次开4个字节),在64位操作系统下为24字节(每⼀次开8个字节)。
C语言的字节对齐及#pragmapack的使用

C语言的字节对齐及#pragmapack的使用C编译器的缺省字节对齐方式(自然对界)在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间。
在结构中,编译器为结构的每个成员按其自然对界(alignment)条件分配空间。
各个成员按照它们被声明的顺序在内存中顺序存储(成员之间可能有插入的空字节),第一个成员的地址和整个结构的地址相同。
C编译器缺省的结构成员自然对界条件为“N字节对齐”,N即该成员数据类型的长度。
如int型成员的自然对界条件为4字节对齐,而double类型的结构成员的自然对界条件为8字节对齐。
若该成员的起始偏移不位于该成员的“默认自然对界条件”上,则在前一个节面后面添加适当个数的空字节。
C编译器缺省的结构整体的自然对界条件为:该结构所有成员中要求的最大自然对界条件。
若结构体各成员长度之和不为“结构整体自然对界条件的整数倍,则在最后一个成员后填充空字节。
例子1(分析结构各成员的默认字节对界条界条件和结构整体的默认字节对界条件):struct Test{char x1; // 成员x1为char型(其起始地址必须1字节对界),其偏移地址为0char x2; // 成员x2为char型(其起始地址必须1字节对界,其偏移地址为1float x3; // 成员x3为float型(其起始地址必须4字节对界),编译器在x2和x3之间填充了两个空字节,其偏移地址为4char x4; // 成员x4为char型(其起始地址必须1字节对界),其偏移地址为8};因为T est结构体中,最大的成员为flaot x3,因些此结构体的自然对界条件为4字节对齐。
则结构体长度就为12字节,内存布局为1100 1111 1000。
例子2:#include <stdio.h>//#pragma pack(2)typedef struct{int aa1; //4个字节对齐 1111char bb1;//1个字节对齐 1short cc1;//2个字节对齐 011char dd1; //1个字节对齐 1} testlength1;int length1 = sizeof(testlength1); //4个字节对齐,占用字节1111 1011 1000,length = 12typedef struct{char bb2;//1个字节对齐 1int aa2; //4个字节对齐 01111short cc2;//2个字节对齐 11char dd2; //1个字节对齐 1} testlength2;int length2 = sizeof(testlength2); //4个字节对齐,占用字节1011 1111 1000,length = 12typedef struct{char bb3; //1个字节对齐 1char dd3; //1个字节对齐 1int aa3; //4个字节对齐 001111short cc23//2个字节对齐 11} testlength3;int length3 = sizeof(testlength3); //4个字节对齐,占用字节1100 1111 1100,length = 12typedef struct{char bb4; //1个字节对齐 1char dd4; //1个字节对齐 1short cc4;//2个字节对齐 11int aa4; //4个字节对齐 1111} testlength4;int length4 = sizeof(testlength4); //4个字节对齐,占用字节1111 1111,length = 8int main(void){printf("length1 = %d.\n",length1);printf("length2 = %d.\n",length2);printf("length3 = %d.\n",length3);printf("length4 = %d.\n",length4);return0;}改变缺省的对界条件(指定对界)· 使用伪指令#pragma pack (n),C编译器将按照n个字节对齐。
c语言字节对齐原理

c语言字节对齐原理C语言中的字节对齐原理是指在内存中分配变量存储空间时,为了提高访问效率和内存利用率,系统会按照一定的规则进行对齐操作。
字节对齐原理在C语言中非常重要,对于程序的正确性和性能都有着重要的影响。
字节对齐的原理是为了优化内存访问速度和空间利用率,避免因为不对齐而导致的性能降低。
在C语言中,变量的存储空间是以字节为单位进行分配的,而不同的数据类型在内存中所占的字节数是不同的。
字节对齐的目的是为了确保不同类型的变量在内存中的起始地址是对齐的,这样可以提高访问效率。
C语言中的字节对齐规则是由编译器来决定的,不同的编译器可能有不同的对齐规则。
一般来说,编译器会按照变量的自然对齐大小进行对齐。
自然对齐是指变量所占的字节数,例如char类型的变量自然对齐为1字节,int类型的变量自然对齐为4字节。
在进行字节对齐时,编译器会在变量之间插入一些空白字节,使得变量的起始地址能够满足对齐要求。
这样一来,虽然会浪费一些空间,但可以提高内存的访问效率。
例如,如果int类型的变量要求按4字节对齐,而其起始地址为0x1000,那么在其后紧接着的变量的起始地址就必须是0x1004,即起始地址必须是4的倍数。
字节对齐的规则并不是固定的,它受到编译器的影响。
有些编译器的默认对齐规则可能是按照变量的自然对齐大小来对齐的,而有些编译器可能会有一些特殊的对齐规则。
此外,开发人员也可以通过编译器提供的指令来手动控制字节对齐的方式。
字节对齐的原理和规则虽然复杂,但它对于程序的正确性和性能优化至关重要。
如果变量没有按照正确的对齐方式进行存储,可能会导致内存访问错误,甚至引发程序崩溃。
而且,字节对齐也会影响程序的性能,如果变量没有按照对齐要求进行存储,可能会导致内存访问速度变慢,从而影响程序的执行效率。
为了正确地使用字节对齐,开发人员需要了解编译器的对齐规则,并且在编写代码时遵循这些规则。
在一些特殊情况下,开发人员也可以使用编译器提供的指令来手动控制字节对齐的方式,以满足特定的需求。
C语言对齐

C语言对齐一、为什么要对齐不同的处理器访问内存的方法不同,一般来讲都支持单字节访问。
为了提高效率16位机可能还支持按2字节访问,32位机可能还支持按4字节访问。
按多字节访问一般需要地址对齐。
比如按2字节访问时,要求地址的最低位为0,即按2字节对齐。
按4字节访问时,要求地址的最低2位为0,即按4字节对齐。
如果地址是符合对齐要求的,就可以实现多字节一次访问,提高访问效率。
否则的话则须拆成单个字节逐个访问。
二、C语言的对齐C语言是跨平台的编程语言,他默认的对齐方式是按照变量的长度进行对齐。
比如char 为一个字节对齐,short为2个字节对齐,long为4个字节对齐。
为了提高内存的利用率,对于全局变量,编译器会把所有同长度的变量组合在一起分配空间,空间的首地址符合对齐关系。
比如给所有非零初值的单字节变量分配一块空间。
例1:char a = 1; short b = 0; char c = 0; char d = 3; short e;那么“a”和“d”会被分配在同一块空间,空间首地址为1字节对齐,“b”和“e”会被分配在同一块空间,空间首地址为2字节对齐。
(无初值一般等同于初值为零)三、结构体的对齐结构体里面的变量默认是单独符合对齐规律的(因为结构体的变量必须连续分配,不能够拆分开统一分配)。
通过#pragma pack(x)可以改变默认的对齐规律,把大于“x”字节对齐的变量压缩到“x”字节对齐,小于“x”字节对齐的变量不受影响。
例2:typedef struct{u8 a;u16 b;u32 c;}test1;test1的内存分配如下表:a 填充b bc c c ctypedef struct{u32 c;u16 b;u8 a;}test2;test2的内存分配如下表:c c c c b b a 填充#pragma pack(1) //对于16位和32位,使用1字节压缩对齐会严重影响效率,慎用!typedef struct{u8 a;u16 b;u32 c;}test3;#pragma pack() //恢复默认压缩字节数test3的内存分配如下表:a b b c c c c四、结构体的尾部填充一些编译器(如KEIL)会在结构体的尾部填充,使结构体的大小为其内部最大对齐数的整数倍。
c语言结构体中的数组字节对齐

C语言结构体中的数组字节对齐在C语言中,结构体是一种用户自定义的数据类型,用于将不同类型的数据组合在一起。
结构体中常常包含多个成员变量,其中可能有数组类型的成员变量。
在结构体中使用数组时,需要了解数组字节对齐的概念和规则,以确保内存的最佳利用和访问的效率。
什么是字节对齐字节对齐是指在将数据存储在计算机内存中时,按照特定规则进行调整,以确保数据的存储和访问的效率。
字节对齐的规则可以对齐数据的起始地址或者数据的长度。
计算机中的数据存储是按照字节(Byte)来划分的,一个字节通常由8个二进制位组成。
字节对齐的主要目的是为了节省内存和提高访问效率。
在C语言中,结构体中的成员变量通常按照字节对齐的规则来排列。
C语言结构体中的数组字节对齐规则在C语言中,结构体中的数组字节对齐规则通常遵循以下原则:1.结构体的起始地址必须是所有成员变量所要求对齐方式的最小公倍数。
2.结构体中的每个成员变量的地址必须是它本身的大小的整数倍。
3.结构体的总大小必须是其最大成员变量大小的整数倍。
根据字节对齐规则,如果结构体中的成员变量的累计大小不是字节对齐的倍数,编译器会在成员变量之间添加填充字节,以满足对齐要求。
这些填充字节在结构体的占用空间中不可访问。
填充字节的目的是将后续成员变量的地址对齐,以提高内存访问效率。
数组字节对齐的示例为了更好地理解数组字节对齐的规则,我们来看一个示例。
#include <stdio.h>struct MyStruct {char c;int i;char arr[3];};int main() {struct MyStruct s;printf("sizeof(MyStruct) = %lu\n", sizeof(struct MyStruct));printf("sizeof(s.c) = %lu\n", sizeof(s.c));printf("sizeof(s.i) = %lu\n", sizeof(s.i));printf("sizeof(s.arr) = %lu\n", sizeof(s.arr));return 0;}输出结果:sizeof(MyStruct) = 12sizeof(s.c) = 1sizeof(s.i) = 4sizeof(s.arr) = 3在这个示例中,我们定义了一个包含一个字符类型变量、一个整型变量和一个长度为3的字符数组的结构体MyStruct。
C语言字节对齐

C语言字节对齐字节对齐的由来程序在运行时会将数据临时存放在内存中,芯片内核需要对这些数据进行计算,不断的读取内存以获得数据,并将计算结果写入内存。
计算机体系经过若干年的发展,最终确定了以8bits作为其基本的存储单元——byte(字节),这是每个地址所对应的最小访问单元,在C语言中对应一个char型的变量。
下图为芯片内核访问内存的示意图。
芯片内核通过控制总线控制内存的动作,通过地址总线告知内存地址,数据总线上出现交互的数据。
图1访问内存示意图假设上图是8位机的示意图,那么数据总线的宽度是8bits,由8根数据线组成,这样芯片内核与内存之间一次就可以同时交换8个bits的数据,正好是一个字节。
图中右侧的每个小格子代表一个存储地址,对应一个字节。
下面通过一段C语言代码来具体看看芯片内核与内存之间的数据交互过程。
char data[2];data[0]=2;data[1]=data[0]+1;第一行代码定义了2个字节的数组data。
假设data数组被编译到地址0x100,那么data[0]这个字节就被存储在地址为0x100的内存空间,data[1]这个字节就被存储在地址为0x101的内存空间。
第二行对应的硬件动作是将数据2存入到data[0]中,也就是将数据2存入到内存中的0x100地址,执行这条语句时,芯片内核对控制总线、地址总线和数据总线进行操作,控制总线上出现写信号,地址总线上出现数据0x100,数据总线上出现数据0x02。
此时内存就知道需要将数据2写入到地址0x100中,完成一次写操作。
第三行先读出data[0]中的数据,芯片内核将控制总线置为读信号,将地址总线置为0x100,此时,内存就会从其内部取出0x100地址中的数据,也就是数据2,2将出现在数据总线上,此时芯片内核就会通过数据总线读取到data[0]中的数据了。
接下来芯片内核计算2+1=3,需要将数字3写入到data[1]中,芯片内核将控制总线置为写信号,将地址总线置为0x101,将数据总线置为3,内存接收到这些信号后,就会将数据3存入到其内部0x101地址中,完成本次操作。
c语言 字节对齐 复位
c语言字节对齐复位C语言中的字节对齐和复位是编程中常用的概念,它们对于数据在内存中的存储和访问起到了重要的作用。
本文将从字节对齐和复位的定义、原理和使用等方面进行阐述。
一、字节对齐字节对齐是指在结构体或联合体中,成员变量按照一定的规则进行排列,以保证数据在内存中的存储效率和访问速度。
在C语言中,结构体或联合体的成员变量是按照其自身的大小进行存储的,但在实际存储时,会按照特定的对齐规则进行对齐。
1.1 对齐规则在C语言中,对齐规则主要由编译器和处理器共同决定。
一般而言,对齐规则要求结构体或联合体的起始地址必须是其成员变量大小的整数倍。
常见的对齐规则有以下几种:- 默认对齐规则:结构体或联合体的每个成员变量按照其自身的大小进行对齐。
- 最紧凑对齐规则:结构体或联合体的每个成员变量按照其自身大小进行对齐,但整个结构体或联合体的大小会进行调整,使得成员变量之间没有空隙。
- 指定对齐规则:使用特定的对齐方式进行对齐,如#pragma pack(n),其中n为指定的对齐字节数。
1.2 对齐原理字节对齐的原理是为了提高内存访问的效率。
在许多体系结构中,对齐的数据访问速度要快于非对齐的数据访问速度。
这是因为处理器在读取内存时,通常是按照字节、半字(2字节)或字(4字节)的方式进行的。
如果数据的起始地址不是对齐的,处理器就需要进行额外的操作,将数据拆分成多次访问,从而降低了访问速度。
1.3 对齐示例下面以一个结构体为例,说明字节对齐的过程:```cstruct example {char c; // 1字节int i; // 4字节double d; // 8字节};```根据默认对齐规则,该结构体的大小为1字节+4字节+8字节=13字节。
但是,由于int类型和double类型的对齐要求通常为4字节和8字节,所以结构体的大小将会调整为16字节,以保证对齐。
二、复位复位是指将内存中的数据清零,即将所有的位设置为0。
C语言的位域,字节对齐
C的位域(bit fields )struct bs{int a:7;int b:2;int c:1;};表示用一个整数的前8位表示a,用一个整数的2位表示b,用一个整数的1位的来表示c,位域定义不能超过数据定义类型的最大位,如struct {char a:9; //char 最大值为8位int b:33; //int 的最大值为32,不能超过其中定义值}位域有如下特殊定义,1)只要不超过数据定义最大值,多个位域可以定义一个数据单位里,如下是合法,定义,也是常用定义Struct PC_PIN{Char bit0:1,bit1:1,Bit2:1,Bit3:1,Bit4:1,Bit5:1,Bit6:1,Bit7:1;}2)位域可以采用’匿名',定义,这样程度就不能使用这些位,这样定义纯粹是起占位用.struct foo1 {int a : 1;int : 2;short c : 1;};上例中,在a和c中有一个2位的匿名占位struct bs{unsigned a:4unsigned :0 /*空域*/unsigned b:4 /*从下一单元开始存放*/unsigned c:4}在这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。
位域占位计算有点复杂1.定义位域不足一个数据位的,按一个完整数据算Struct tagA{Int a:3;Int b;};Sizeof()值是8,因为a仍然按4位来核算.2.如果连续定义几点相同类型.而位域总合不超过类型总位数长度的,会被编译器设为一个合并为一个位域定义如struct tagA{int a:1;int b:2;int c;3}等同于struct tagB{Int a:1,b:2,c:3;};Sizeof()的长度都是4,因为tagA的各个成员加起长度都没有超过32,所以仍然为43.aaa位域的被广泛应用于8位单片机编程中.因为一个8位寄存器刚好是一个char 的宽度,因为可以定义一个8个位位域来对寄存器的各个位进行存取.这样程序比较简单并且好理解.但在32位CPU应用反而不广泛,因为32CPU的寄存器是为32位宽度,正好是一个int 的宽度,但int 在不同CPU中的表示顺序位是不一致的.在不同字节序CPU里定义的位域,有一些不样,换句话说,定义这样位域需要定义两套类型.如ip的头定义.struct iphdr {#if defined(__LITTLE_ENDIAN_BITFIELD)__u8 ihl:4,version:4;#elif defined (__BIG_ENDIAN_BITFIELD)__u8 version:4,ihl:4;#else#error "Please fix <asm/byteorder.h>"#endif__u8 tos;__u16 tot_len;__u16 id;__u16 frag_off;__u8 ttl;__u8 protocol;__u16 check;__u32 saddr;__u32 daddr;/*The options start here. */};使用反而不如位操作定义方便,因此32位CPU使用位域有一些麻烦字节对齐现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但为为了CPU访问数据的快速,通常都要求数据存放的地址是有一定规律的.比如在32位CPU上,一般要求变量地址都是基于4位,这样可以保证CPU用一次的读写周期就可以读取变量.不按4位对齐,如果变量刚好跨4位的吗,这样需要CPU两个读写周期.效率自然低下.因此,在现代的编译器都会自动把复合数据定义按4位对齐,以保证CPU 以最快速度读取,如下例(gcc version 编译器(32位x86平台))struct A {int a;char b;short c;};结构体A中包含了4字节长度的int一个,1字节长度的char一个和2字节长度的short 型数据一个。
C语言字节对齐__align()讲解
在设计不同 CPU 下的通信协议时,或者编写硬件驱动程序时寄存器的结构这两个地 方都需要按一字节对齐。即使看起来本来就自然对齐的也要使其对齐,以免不同的编译器生 成的代码不一样.
一、快速理解 1. 什么是字节对齐? 在 C 语言中,结构是一种复合数据类型,其构成元素既可以是基本数据类型(如 int、long、 float 等)的变量,也可以是一些复合数据类型(如数组、结构、联合等)的数据单元。在 结构中,编译器为结构的每个成员按其自然边界(alignment)分配空间。各个成员按照它 们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。 为了使 CPU 能够对变量进行快速的访问,变量的起始地址应该具有某些特性,即所谓的”对 齐”. 比如4字节的 int 型,其起始地址应该位于4字节的边界上,即起始地址能够被4整除. 2. 字节对齐有什么作用? 字节对齐的作用不仅是便于 cpu 快速访问,同时合理的利用字节对齐可以有效地节省存储空 间。 对于32位机来说,4字节对齐能够使 cpu 访问速度提高,比如说一个 long 类型的变量,如果 跨越了4字节边界存储,那么 cpu 要读取两次,这样效率就低了。但是在32位机中使用1字节 或者2字节对齐,反而会使变量访问速度降低。所以这要考虑处理器类型,另外还得考虑编 译器的类型。在 vc 中默认是4字节对齐的,GNU gcc 也是默认4字节对齐。 3. 更改 C 编译器的缺省字节对齐方式 在缺省情况下,C 编译器为每一个变量或是数据单元按其自然对界条件分配空间。一般地, 可以通过下面的方法来改变缺省的对界条件: · 使用伪指令#pragma pack (n),C 编译器将按照 n 个字节对齐。 · 使用伪指令#pragma pack (),取消自定义字节对齐方式。 另外,还有如下的一种方式: · __attribute((aligned (n))),让所作用的结构成员对齐在 n 字节自然边界上。如果结 构中有成员的长度大于 n,则按照最大成员的长度来对齐。 · __attribute__ ((packed)),取消结构在编译过程中的优化对齐,按照实际占用字节数 进行对齐。 4. 举例说明 例1 struct test { char x1; short x2; float x3; char x4; }; 由于编译器默认情况下会对这个 struct 作自然边界(有人说“自然对界”我觉得边界更顺 口)对齐,结构的第一个成员 x1,其偏移地址为0,占据了第1个字节。第二个成员 x2为 short 类型,其起始地址必须2字节对界,因此,编译器在 x2和 x1之间填充了一个空字节。结构的 第三个成员 x3和第四个成员 x4恰好落在其自然边界地址上,在它们前面不需要额外的填充 字节。在 test 结构中,成员 x3要求4字节对界,是该结构所有成员中要求的最大边界单元, 因而 test 结构的自然对界条件为4字节,编译器在成员 x4后面填充了3个空字节。整个结构 所占据空间为12字节。 例2 #pragma pack(1) //让编译器对这个结构作1字节对齐
c语言4字节对齐指令
C语言4字节对齐指令一、什么是对齐指令1.1 对齐的概念在计算机中,对齐是指数据在内存中存储的方式。
内存中的数据是以字节为单位进行存储的,而对齐就是数据在内存中存储时的起始位置需要与其自身的大小对齐。
1.2 对齐的优势对齐的目的是为了提高计算机的访问速度。
当数据对齐之后,CPU的访问操作会更加高效,从而提高程序的执行效率。
二、数据对齐的原则数据的对齐有一定的规则,其中最常见的是按照字节对齐的原则进行排列。
2.1 字节对齐原则在C语言中,数据的字节对齐原则是根据数据类型的大小来确定的。
一般来说,对于基本数据类型,其对齐规则如下所示:•char类型不需要对齐,可以从任意位置开始存储。
•short类型需要2字节对齐,即起始地址必须是2的倍数。
•int类型需要4字节对齐,即起始地址必须是4的倍数。
•long类型需要8字节对齐,即起始地址必须是8的倍数。
2.2 结构体对齐原则对于结构体中的成员变量,其对齐规则也是按照字节对齐的原则进行排列的。
结构体中的成员变量按照其自身的大小顺序存放,并且每个成员变量的起始地址需要满足对齐规则。
三、C语言的对齐指令C语言提供了一些对齐指令,可以用来控制数据的对齐方式。
对齐指令可以通过编译器的选项来设置,也可以使用特殊的关键字进行设置。
3.1 编译器选项设置对齐方式编译器提供了一些选项来设置数据的对齐方式,其中最常用的是-malign-double 选项。
该选项可以控制double类型的对齐方式,一般情况下,我们可以将其设置为-malign-double=8,表示使用8字节对齐方式。
3.2 结构体的对齐指令在C语言中,可以使用#pragma pack(n)指令来设置结构体的对齐方式。
其中n表示对齐的字节数,常用的值为1、2、4、8等。
3.3 成员变量的对齐指令对于结构体中的某个成员变量,可以使用__attribute__((aligned(n)))指令来单独设置其对齐方式,其中n表示对齐的字节数。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
什么是字节对齐,为什么要对齐
现代计算机中内存空间都是按照BYTE划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。
作用和原因:
各个硬件平台对存储空间的处理上有很大的不同。
一些平台对某些特定类型的数据只能从某些特定地址开始存取。
比如有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对数据存放进行对齐,会在存取效率上带来损失。
比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数据。
以下内容节选自《Intel Architecture 32 Manual》。
字,双字,和四字在自然边界上不需要在内存中对齐。
(对字,双字,和四字来说,自然边界分别是偶数地址,可以被4整除的地址,和可以被8整除的地址。
)
无论如何,为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。
原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;然而,对齐的内存访问仅需要一次访问。
一个字或双字操作数跨越了4字节边界,或者一个四字操作数跨越了8字节边界,被认为是未对齐的,从而需要两次总线周期来访问内存。
一个字起始地址是奇数但却没有跨越字边界被认为是对齐的,能够在一个总线周期中被访问。
某些操作双四字的指令需要内存操作数在自然边界上对齐。
如果操作数没有对齐,这些指令将会产生一个通用保护异常(#GP)。
双四字的自然边界是能够被16 整除的地址。
其他的操作双四字的指令允许未对齐的访问(不会产生通用保护异常),然而,需要额外的内存总线周期来访问内存中未对齐的数据。
一次访问时,要么读0x01~0x04,要么读0x05~0x08……
硬件不支持一次访问就读到0x02~0x05
举个例子,如果0x02~0x05存了一个int,读取这个int就需要先读0x01~0x04,留下0x02~0x04的内容,再读0x05~0x08,留下0x05的内容,两部分拼接起来才能得到那个int的值……
读一个int就要两次内存访问,效率就低了……
字节对齐要区分四个概念
1、基本数据类型的自身对齐值:
1字节:char型
2字节:short型
4字节:int,float类型
8字节:doublel类型
2、程序的指定对齐值:即#pragma pack(value)时的指定对齐值value
3、自定义类型的自身对齐值:结构体或类的成员中自身对齐值最大的值
4、自定义类型的有效对齐值:自定义类型的自身对齐值和指定对齐值中较小的值
据此,我们就可以很方便的来讨论具体数据结构的成员和其自身的对齐方式。
#pragma pack(4)
Struct test
{
Char a;
Short b;
Char c;
};
上述结构体S的自身对齐值为2(b的自身对齐值),而指定对齐值为4(32位编译器默认值),故最终的有效对齐值为2.
位域
位域是指信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。
例如在存放一个开关量时,只有0和1 两种状态,用一位二进位即可。
为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。
所谓“位域”是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。
每个域有一个域名,允许在程序中按域名进行操作。
这样就可以把几个不同的对象用一个字节的二进制位域来表示。
位域定义的几点说明
对于位域的定义尚有以下几点说明:
1. 一个位域必须存储在同一个字节中,不能跨两个字节。
如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。
也可以有意使某位域从下一单元开始。
例如:
struct bs
{unsigned a:4unsigned :0 /*空域*/unsigned b:4 /*从下一单元开始存放*/unsigned c:4}
在这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。
2. 位域的长度不能大于指定类型固有长度,比如说int的位域长度不能超过32,bool的位域长度不能超过8。
3. 位域可以无位域名,这时它只用来作填充或调整位置。
无名的位域是不能使用的。
例如:
struct k
{int a:1int :2 /*该2位不能使用*/int b:3int c:2};
从以上分析可以看出,位域在本质上就是一种结构类型,不过其成员是按二进位分配的。