字节对齐



今天我们总结在C++和C语言中让我们头疼的字节对齐问题:



一、首先来看什么是字节对其?

现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任

何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。

二: 那么问题就来了为什么要字节对其?以及字节对其的作用?

各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对

数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int

型(假设为32位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数

据。显然在读取效率上下降很多。



三、如何计算字节对齐

1、ok弄清了什么是字节对其,以及字节对其的作用和影响,下来让我们看字节是如何对其的:

首先这个字节对其与平台有关,我们先用VC++6.0测试出Win32架构下各基本数据类型所占的字节:





2、然后我们来看编译器进行字节对其遵循的原则都是什么?编译进行字节对其时,遵循以下四个原则:



1.数据类型自身的对齐值:
   对于char型数据,其自身对齐值为1,对于short型为2,对于int,float,double类型为4单位字节。其自身对齐值也就是上图我求的基本数据类型的大小。

2.结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值。
3.指定对齐值:#pragma pack (value)时的指定对齐值value。
4.数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值。



有了以上四个原则就可以判断一个结构的大小。

最终用来决定数据存放地址方式的值,最重要。有效对齐N,就是表示“对齐在N上”,也就是说该数据的"存放起始地址%N=0".而数据结构中的数据变量都是按定义的先后顺序来排放的。第一个数据变量的起始地址就是数 据结构的起始地址。结构体的成员变量要对齐排放,结构体本身也要根据自身的有效对齐值圆整(就是结构体成员变量占用总长度需要是对结构体有效对齐值的整数倍,结合下面例子理解)。这样就不能理解上面的几个例子的值了。

例子分析:
    1、对于结构体只有基本数据类型以及构成的

struct Test1              //
{     char a;        //1
      int b;             //4   
      short c;
 };

下边是测试结果:

对于这种情况我们来分析以下:

对于字节对其,我们始终要关注一个结构体的有效对齐值,编译器默认对齐值一般是4个字节,有效值取结构体自身对齐值和指定对齐值的最小值,按照我的理解,我们在计算字节对其时,可以这样计算:从第一个元素开始计算,a自身对齐值是1,系统默认对齐值是4,所以此时结构体自身对齐值是1,因而此时a不用补齐,到b时,b的自身对齐值是4字节,那么此时结构体的自身对齐值是4字节,但是刚才的a又不是4的整数倍,因而又要退回去给a补三个字节,接着往下走,c的自身自身对齐值是2个字节,结构体的自身对齐值取结构体中的最大值,所以此时结构体的自身对齐值依然是4字节,4是2的整数倍,所以不用补齐,最后a,b,c总大小是10个字节不是4的倍数,最后再补两个字节。所以结构体的大小是12个字节。

事实上,一个结构体出来以后,自身对齐值,也就出来了,自身对齐值,取结构体中数据成员最大值。然后再一一与结构体的成员比较对齐。最后根据有效对齐值,确定结构体的最终空间大小。

2、空结构体的大小

在标C中不允许出现空的结构体,C++中允出现空的结构体分配一个字节的空间

3、结构中有数组的情况

    对于这种情况,还是按照上面分析的,先找出结构体的自身对齐值,然后补齐对齐。最后结构体的大小由结构体有效对齐值决定。

看测试案例:

4、结构体中嵌套结构体

  注意:这里有一个细节需要注意如果结构体中嵌套的结构体没有定义结构体变量的话不分配一个字节的大小,这相当于只是告诉编译器有这么一种类型,类型是不占 大小,只有分配变量后才有空间和大小。这种情况下,结构体的大小由其它成员决定。

同样的结构,我在内部结构体中加一个变量,结果就完全不一样,

          对于这种结构,我们是按照先分析内部结构,计算出内部结构的大小,以及自身对齐值,然后按照一般的在计算外部结构的。具体分析这道题:

对于Test结构:系统默认的对齐值是四个字节,当到第一个元素ch时ch的自身对齐值是1,则此时结构体的自身对齐值是1,,所以此时ch不用补齐,然后d时,double的自身对齐值是8字节,那么此时结构体的自身对齐值是8字节,d不用补齐,而ch需要补齐8字节,此时,ch补7个字节个字节,此时结构体一共16个字节,而最后结构体的大小还要看结构体有效对齐值,此时结构体自身对齐值是8,系统默认对齐值是4字节,16是4整数倍,所以内部结构体的最后大小就是16字节。此时Test与外部其他数据成员比较时,内部结构来说要看成一个数据类型,它的自身对齐值是8字节,但是内部结构体本身依然是开辟16字节的,对于外部结构体,自身对齐值取数据成员自身对齐值最大的,这里也就是8字节。此时外部结构的空间大小一共24字节,而我们说过结构体最终空间的大小由有效值决定,此时外部结构体有效值是4字节,而24是4字节的整数倍所以结构体的最终大小是24字节。

编译器一帮默认是4字节对齐,可以通过加命令调整默认对其方式,对于结构体来说,加了这条命令依然最后结构体的大小按照最后取小的计算,所以对于上面的情况只是多一个参考值。

4、联合体空间大小

对于联合体的大小取数据成员的最大值,但是联合体最终大小还是由联合体的自身对齐值决定,联合体最后的大小必须是自身对齐值整数倍。注意这里是自身对齐值,不是有效值。并且它不受pragma pack()的影响。

具体看下面代码,也就是说,对于tes来说自身对齐值是8,联合体的大小取最大的这里也就是ch13和字节,但是它不是8的整数倍,所以补3个字节。



以上就是我的理解,如果有不对的地方,欢迎各位指正。



本文出自 “12162969” 博客,请务必保留此出处http://12172969.blog.51cto.com/12162969/1955249

时间: 2024-12-30 09:03:35

字节对齐的相关文章

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语言:内存字节对齐详解[转载]

一.什么是对齐,以及为什么要对齐: 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

结构体字节对齐

结构体字节对齐 在用sizeof运算符求算某结构体所占空间时,并不是简单地将结构体中所有元素各自占的空间相加,这里涉及到内存字节对齐的问题.从理论上讲,对于任何 变量的访问都可以从任何地址开始访问,但是事实上不是如此,实际上访问特定类型的变量只能在特定的地址访问,这就需要各个变量在空间上按一定的规则排列, 而不是简单地顺序排列,这就是内存对齐. 内存对齐的原因: 1)某些平台只能在特定的地址处访问特定类型的数据: 2)提高存取数据的速度.比如有的平台每次都是从偶地址处读取数据,对于一个int型的

C/C++中避免系统的字节对齐

在定义了一个新的Struct后. 系统会按照一定的规则将新生命的类型变量进行字节对齐,如下结构体: typedef struct Test{ int a; char b[6]; }Test; 该结构体类型可能会被对齐为12个字节. 那么,在内存流和文件流操作中可能会出现这样的用法: fwrite(strPtr,1,sizeof(Test)*len,fp); 事实上,被写入了len*12个字节,因为sizeof(Test)实际上不等于10,而是12. 那么,如下简单地操作可以避免在流操作中出现的一

内存字节对齐

写出一个struct,然后sizeof,你会不会经常对结果感到奇怪?sizeof的结果往往都比你声明的变量总长度要大,这是怎么回事呢?讲讲字节对齐吧 1:数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,结构体等)的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储. 2:结构体作为成员:如果一个结构里有某些结构

字节对齐问题

文章最后本人做了一幅图,一看就明白了,这个问题网上讲的不少,但是都没有把问题说透. 32位机器上各种数据类型的长度如下:char:1(有符号无符号同) short:2(有符号无符号同) int:4(有符号无符号同) long:4(有符号无符号同) float:4 double:8 一.概念    对齐跟数据在内存中的位置有关.如果一个变量的内存地址正好位于它长度的整数倍,他就被称做自然对齐.比如在32位cpu下,假设一个整型变量的地址为0x00000004,那它就是自然对齐的.   二.为什么要

C语言字节对齐 __align(),__attribute((aligned (n))),#pragma pack(n)

转载地址 : http://blog.csdn.net/21aspnet/article/details/6729724 一.概念    对齐跟数据在内存中的位置有关.如果一个变量的内存地址正好位于它长度的整数倍,他就被称做自然对齐.比如在32位cpu下,假设一个整型变量的地址为0x00000004,那它就是自然对齐的.   二.为什么要字节对齐   需要字节对齐的根本原因在于CPU访问数据的效率问题.假设上面整型变量的地址不是自然对齐,比如为0x00000002,则CPU如果取它的值的话需要访