字节对齐原理

1.  字节对齐:

现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量(内置类型)的时候经常在特 定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。

2.  字节对齐的原因:

各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问 一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对 数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那 么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数 据。显然在读取效率上下降很多。

默认CPU总线读取4字节,然后根据类型剔除,变量存放的地址能够整除变量类型,

、,因为它的起始地址是0,因此肯定是对齐的,之所以在后面补充2个字节,是因为编译器为了实现结构数组的存取效率,试想如果我们定义了一个结构B的数组,那么第一个结构起始地址是0没有问题,但是第二个结构呢?按照数组的定义,数组中所有元素都是紧挨着的,如果我们不把结构的大小补充为4的整数倍,那么下一个结构的起始地址将是0x0000A,这显然不能满足结构的地址对齐了,因此我们要把结构补充成有效对齐大小的整数倍.

3. 设置对齐方式

#pragma pack(n),设置按照n字节对齐,每个类型成员的存放地址可以整除n;#pragma pack(),取消对齐方式,默认形式为4字节对齐;

4.编译器的对齐原则

a.  对于内置类型来说,按照自身的类型大小对齐,char存放的地址可以整除1,int,float 可以整除4,double可以整除8,short可以整除2;

b.   结构体和类的自定义类型,对齐方式按照数据成员最大类型方式存取。

c.   指定对齐值:#pragma pack (value)时的指定对齐值value。

d.  最终存放所需的字节 数要能乘除最大类型

e. 结构体数组也是字节对齐

5.修改编译器的字节对齐;

.在VC IDE中,可以这样修改:[Project]|[Settings],c/c++选项卡Category的Code Generation选项

的Struct Member Alignment中修改,默认是8字节。 2.在编码时,可以这样动态修改:#pragma pack .注意:是pragma而不是progma.

6.  ARM编译器对齐方式

对齐的使用: 1.__align(num)     这个用于修改最高级别对象的字节边界。在汇编中使用LDRD或者STRD时     就要用到此命令__align(8)进行修饰限制。来保证数据对象是相应对齐。     这个修饰对象的命令最大是8个字节限制,可以让2字节的对象进行4字节     对齐,但是不能让4字节的对象2字节对齐。     __align是存储类修改,他只修饰最高级类型对象不能用于结构或者函数对象。    2.__packed    __packed是进行一字节对齐    1.不能对packed的对象进行对齐    2.所有对象的读写访问都进行非对齐访问    3.float及包含float的结构联合及未用__packed的对象将不能字节对齐    4.__packed对局部整形变量无影响    5.强制由unpacked对象向packed对象转化是未定义,整形指针可以合法定    义为packed。       __packed int* p;   //__packed int 则没有意义    6.对齐或非对齐读写访问带来问题    __packed struct STRUCT_TEST {    char a;    int b;    char c; }   ;     //定义如下结构此时b的起始地址一定是不对齐的           //在栈中访问b可能有问题,因为栈上数据肯定是对齐访问[from CL] //将下面变量定义成全局静态不在栈上 static char* p; static struct STRUCT_TEST a; void Main() { __packed int* q;   //此时定义成__packed来修饰当前q指向为非对齐的数据地址下面的访问则可以 p = (char*)&a;          q = (int*)(p+1);

*q = 0x87654321; /*   得到赋值的汇编指令很清楚 ldr       r5,0x20001590 ; = #0x12345678 [0xe1a00005]    mov       r0,r5 [0xeb0000b0]    bl        __rt_uwrite4   //在此处调用一个写4byte的操作函数       [0xe5c10000]    strb      r0,[r1,#0]    //函数进行4次strb操作然后返回保证了数据正确的访问 [0xe1a02420]    mov       r2,r0,lsr #8 [0xe5c12001]    strb      r2,[r1,#1] [0xe1a02820]    mov       r2,r0,lsr #16 [0xe5c12002]    strb      r2,[r1,#2] [0xe1a02c20]    mov       r2,r0,lsr #24 [0xe5c12003]    strb      r2,[r1,#3] [0xe1a0f00e]    mov       pc,r14 */ /* 如果q没有加__packed修饰则汇编出来指令是这样直接会导致奇地址处访问失败 [0xe59f2018]    ldr       r2,0x20001594 ; = #0x87654321 [0xe5812000]    str       r2,[r1,#0] */ //这样可以很清楚的看到非对齐访问是如何产生错误的 //以及如何消除非对齐访问带来问题 //也可以看到非对齐访问和对齐访问的指令差异导致效率问题 }

时间: 2024-08-01 11:20:40

字节对齐原理的相关文章

字节对齐原理1

1.  字节对齐: 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量(内置类型)的时候经常在特 定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐. 2.  字节对齐的原因: 各个硬件平台对存储空间的处理上有很大的不同.一些平台对某些特定类型的数据只能从某些特定地址开始存取.比如有些架构的CPU在访问 一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编

bmp图像存储中的字节对齐问题

1. bmp数据对齐问题. 假设所读取的bmp图片位数是24,图像高度和宽度分别为998像素和726像素,每个像素占3个字节,即每行像素占3*726个字节,不是4的整数倍,首先需要对每行字节进行补零操作.假设文件头和信息头分别为bfh和bih,则每行所补的字节数为: offset_bytes = 4 - (bih.biWidth * bih.biBitCount/8)%4 补齐后每行所占的字节数为: row_length = 4*((bih.biWidth * bih.biBitCount +

C++字节对齐问题

关于C++字节对齐问题 关于C/C++的字节对齐 这两天写解析SWF文件的程序,在结构体指针和从文件里读出来的进行转换的时候遇到一些问题,就是有一个struct A,比如: struct A { char flag; int length; int id; .... }; 然后一个飘逸的 struct A *a = (struct A*)buffer;   // 世界一下清静咯 可惜在输出a中的成员的时候却发现老是不对,百思不得起解.今晚一想,可能是因为C++的字节对齐问题,所以直接就百度了一些

golang 字节对齐

最近在做一些性能优化的工作,其中有个结构体占用的空间比较大,而且在内存中的数量又特别多,就在想有没有优化的空间,想起了 c 语言里面的字节对齐,通过简单地调整一下字段的顺序,就能省出不少内存,这个思路在 golang 里面同样适用 基本数据大小 在这之前先来看下 golang 里面基本的类型所占数据的大小 So(unsafe.Sizeof(true), ShouldEqual, 1) So(unsafe.Sizeof(int8(0)), ShouldEqual, 1) So(unsafe.Siz

stm32中字节对齐问题

ARM下的对齐处理   from DUI0067D_ADS1_2_CompLib 3.13 type  qulifiers 有部分摘自ARM编译器文档对齐部分  对齐的使用:  1.__align(num)     这个用于修改最高级别对象的字节边界.在汇编中使用LDRD或者STRD时     就要用到此命令__align(8)进行修饰限制,来保证数据对象是相应对齐.     这个修饰对象的命令最大是8个字节限制,可以让2字节的对象进行4字节     对齐,但是不能让4字节的对象2字节对齐.  

字节对齐

今天我们总结在C++和C语言中让我们头疼的字节对齐问题: 一.首先来看什么是字节对其? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任 何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐. 二: 那么问题就来了为什么要字节对其?以及字节对其的作用? 各个硬件平台对存储空间的处理上有很大的不同.一些平台对某些特定类型的数据只能从某些特定地址开始存

C语言:内存字节对齐详解[转载]

一.什么是对齐,以及为什么要对齐: 1. 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定变量的时候经常在特定的内存地址访问,这就需要各类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐. 2. 对齐的作用和原因:各个硬件平台对存储空间的处理上有很大的不同.一些平台对某些特定类型的数据只能从某些特定地址开始存取.其他平台可能没有这种情况, 但是最常见的是如果不按照适合其平台的要求对数据存放进行对齐

结构体字节对齐问题(转)

原文出处:http://wenku.baidu.com/view/019e26b765ce0508763213e2.html 初学C,对结构体的使用sizeof计算所占字节数不是很明白,看了此篇文章,终于豁然开朗,转载过来,方便以后温故. #include<stdio.h> struct a {   char no[10];   int p;   long int pp;   unsigned int ppp;   char x;   float y;   double h; }xy; voi

关于C/C++的字节对齐

为什么要字节对齐呢?这要从计算机的结构说起,我们知道,在C/C++中定义的变量有单字节(char),双字节(short),四字节(int,float),八字节(long),但是CPU并不一个字节一个字节来读取处理的(8位单片机除外哈),目前常见的CPU都是32位甚至64位,这意味着CPU一次要读取4个字节或者8个字节,并且不能从任意地址开始读取,只能从地址是4或8的倍数地方开始.所以,要是一个int型数据正好被4或8的倍数分成两块呢,那CPU只能分两次来读,效率当然降低了,而如果浪费点内存,把c