精华内容
下载资源
问答
  • C语言字节对齐规则总结
    千次阅读 多人点赞
    2018-10-23 16:16:30

    原始链接源自 https://www.cnblogs.com/clover-toeic/p/3853132.html , 从上面博客中学习总结得到下面的文章。

        不同硬件平台,对存储空间的处理不一样,比如不能放奇数地址,不能任意存放等,为了适应不同的架构,在C语言层面上,就可以执行对齐从而独立于硬件平台。 此外,是由于对内存的存取效率问题,如果存放的地址不对齐,取一个4字节的数据,可能会需要两个时钟信号才能取完。为了CPU能够对数据进行快速的访问,也要求数据的起始地址具有对齐特性。 比如4字节数据的起始地址应该在4字节的边界上,也就是数据存放的起始地址应该被4整除。这就是为什么要字节对齐, 和什么是字节对齐。

     

        对齐的方式,又区分 结构体对齐、 栈内存对齐、位域对齐, 位域本质上是结构体。

        对于Intel X86平台,每次分配内存应该是从4的整数倍地址开始分配,无论是对结构体变量还是简单类型的变量。

    一、结构体对齐
        编译器为结构体的每个成员按照其自然边界(alignment)分配空间。各成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。

        对齐规则:

     1) 数据类型自身的对齐值:char型数据自身对齐值为1字节,short型数据为2字节,int/float型为4字节,double型为8字节。

     2) 结构体的自身对齐值:其成员中自身对齐值最大的那个值

     3) 指定对齐值:#pragma pack (value)时的指定对齐值value。默认是4。

     4) 数据成员、结构体的有效对齐值:自身对齐值和指定对齐值中较小者,即有效对齐值=min{自身对齐值,当前指定的pack值}。

        使用pragma指定对齐值,其实是指定了数据结构的最大对齐值, 如果本身的对齐值,并不超过设定的值,还是会按照自身的对齐值来。

        有效对齐值N是最终用来决定数据存放地址方式的值。有效对齐N表示“对齐在N上”,即该数据的“存放起始地址%N=0”。结构体的成员变量要对齐存放,结构体本身也要根据自身的有效对齐值圆整(即结构体成员变量占用总长度为结构体有效对齐值的整数倍)。

    struct A{
        int    a;
        char   b;
        short  c;
    };
    struct B{
        char   b;
        int    a;
        short  c;
    };

        sizeof(A) = 8,  sizeof(B) = 12;

        A中,最初的int是4字节对齐,char是1字节对齐,所以前5个字节不需要填充,后面short长度为2个字节,和2对齐,所以char后面补一个字节,总共是8个字节。整个数组的有效对齐值是成员的最大值4, 8个字节是4的整数倍, 所以结构体总长度为8。

        B中,最初char是1字节,随后int长度是4字节,和4字节对齐,char后面补3个字节,最后short是第9和10字节,也是对齐的。整个结构体的有效对齐值是4,结构体长度需要是4的整数倍,所以short后面还需要补2个字节,总长度为12。

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

    更改对齐方式:

        在缺省情况下,C编译器为每一个变量或是数据单元按其自然对界条件分配空间。一般地,可以通过下面的方法来改变缺省的对界条件:
        使用伪指令#pragma pack(n):C编译器将按照n个字节对齐;
        使用伪指令#pragma pack(): 取消自定义字节对齐方式。

       在编码时,可用#pragma pack动态修改对齐值。自定义对齐值后要用#pragma pack()来还原,否则会对后面的结构造成影响。

    #pragma pack(2)  //指定按2字节对齐
    struct C{
        char  b;
        int   a;
        short c;
    };
    #pragma pack()   //取消指定对齐,恢复缺省对齐

        char自身对齐值是1,指定对齐值是2,所以有效对齐值是1。 int自身对齐值是4,指定对齐值是2,所有有效对齐值是2,放在2的倍数的地址空间上,char后面只会补1个字节。所以到这里长度是6,后面short两个字节,有效对齐值也是2,结构体总长度是8。

        需要注意,pragma pack指定的对齐值,是数据类型的最大对齐值,可以小,但是不能大。

        因为对齐,会产生的问题:

        1,数据类型强转可能会因为对齐,出错。 short类型应该放在2的倍数的地址上,但是这里p1却指向了奇数地址。需要注意。

    int main(void){  
        unsigned int i = 0x12345678;
            
        unsigned char *p = (unsigned char *)&i;
        *p = 0x00;
        unsigned short *p1 = (unsigned short *)(p+1);
        *p1 = 0x0000;
    
        return 0;
    }

        2,不同的处理器之间传递数据时,因为两个处理器可能采用的填充方式不一致,会导致数据出错。这时,可以在定义数据结构时,自己把需要填充的部分用char类型的数据填上,这样就不会不一致了。或者使用pragma pack 1, 让数据都按照1字节对齐。

    二、栈内存对齐

    在VC/C++中,栈的对齐方式不受结构体成员对齐选项的影响。总是保持对齐且对齐在4字节边界上。(直接看博客原文吧,他里面说的char和short没有凑到4个字节,我认为是已经凑到一起了)。

    三、位域的对齐方式

        有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1两种状态,用一位二进位即可。为了节省存储空间和处理简便,C语言提供了一种数据结构,称为“位域”或“位段”。

        1,为了节省内存,对于大量的结构体数组来讲。 2,需要访问字节内的bit成员。两种情况会使用位域。

        位域成员,除了指定所占用的bit位外,还有一个类型。位域成员不能单独被取sizeof值。下面主要讨论含有位域的结构体的sizeof。

    其对齐规则大致为:

         1) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;

         2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;

         3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++和GCC采取压缩方式;

         4) 如果位域字段之间穿插着非位域字段,则不进行压缩;

         5) 整个结构体的总大小为最宽基本类型成员大小的整数倍,而位域则按照其最宽类型字节数对齐。

     

         位域可以无位域名,只用作填充或调整位置,占位大小取决于该类型。例如,char :0表示整个位域向后推一个字节,即该无名位域后的下一个位域从下一个字节开始存放,同理short :0和int :0分别表示整个位域向后推两个和四个字节。

         当空位域的长度为具体数值N时(如int :2),该变量仅用来占位N位。

        原文还有位域的例子和字节大小端的例子,在这里就不写了。

    更多相关内容
  • C语言 字节对齐

    2022-03-29 17:05:33
    结构体变量的首地址能够被其最宽基本类型成员的大小所整除; 结构体每个成员相对结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要...// char[*]多少都是按4字节对齐 struct stChar{ char a[5]; int b; .

    字节对齐 、pragma 、位域长度问题整理

    1. 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
    2. 结构体每个成员相对结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节;
    3. 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。
    #include <stdio.h>
    // 按结构体最宽数据类型int对齐
    // char[*]多少都是按4字节对齐
    struct stChar{
            char a[5];
            int b;
            char c;
    };
    
    // 按结构体最宽数据类型short对齐
    struct stShort{
            char a;
            short b;
    };
    
    // 按结构体最宽数据类型long对齐
    struct stLong{
            char a;
            long b;
    };
    
    // 按结构体最宽数据类型int对齐
    // 变量c的偏移量 要为自己大小的倍数
    #pragma pack(8) //为2时,sizeof为10.为8时sizeof为12 
    struct AA
    {
            int a;  
            char b; 
            short c; //长度2 偏移量要提升到2的倍数6;存放位置区间[6,7]
            char d; 
    };
    
    struct AAA
    {
            // 类型说明符 位域名: 位域长度
            int a:2; //变量a,4位长度,只使用两位长度 sizeof(AAA)为4
            char b:1;
    };
    
    int main()
    {
            struct stChar stChar1;
            struct stShort stShort1;
            struct stLong stLong1;
            struct AA stAA;
            struct AAA stAAA;
    
            printf("stChar = [%ld]\n", sizeof(stChar1));
            printf("stShort = [%ld]\n", sizeof(stShort1));
            printf("stLong = [%ld]\n", sizeof(stLong1));
            printf("stAA = [%ld]\n", sizeof(stAA));
            printf("stAAA = [%ld]\n", sizeof(stAAA));
            return 0}
    

    打印结果

    stChar = [16]
    stShort = [4]
    stLong = [16]
    stAA = [12]
    stAAA = [4]
    
    展开全文
  • c语言字节对齐

    2021-11-26 11:15:16
    c语言驱动变成,网络通讯内核模块编程

    c语言结构体字节对齐详解

    正在上传…重新上传取消​cpp加油站发布于 4 月 22 日

    1.什么是字节对齐

    在c语言的结构体里面一般会按照某种规则去进行字节对齐。

    我们先看一段代码:

    struct st1
    {
        char name;
        double age;
        char sex;
    };
    //32位下 sizeof(struct st1) = 16
    //64位下 sizeof(struct st1) = 24
    struct st2
    {
        char a;
        char b;
        char c;
    };
    //32位和64位下, sizeof(struct st2)都是3个字节

    从以上结果可以看出,结构体st1在32位下是按照4个字节来对齐的,在64位下则是按照8个字节来对齐的,结构体st2则不管32位还是64位则都是按照1个字节对齐的。

    那么我们可以总结出对齐规则如下:

    • 在所有结构体成员的字节长度都没有超出操作系统基本字节单位(32位操作系统是4,64位操作系统是8)的情况下,按照结构体中字节最大的变量长度来对齐;
    • 若结构体中某个变量字节超出操作系统基本字节单位,那么就按照系统字节单位来对齐。
    注意:并不是32位就直接按照4个字节对齐,64位按照8个字节对齐。

    2.为什么要有字节对齐

    首先普及一点小知识,cpu一次能读取多少内存要看数据总线是多少位,如果是16位,则一次只能读取2个字节,如果是32位,则可以读取4个字节,并且cpu不能跨内存区间访问。

    假设有这样一个结构体如下:

    struct st3
    {
        char a;
        int b;
    };
    //那么根据我们第1节所说的规则,在32位系统下,它就应该是8个字节的。

    地址空间是类似下面这样的:

    heigh0x00000008
    0x00000007
    0x00000006
    0x00000005
    0x00000004
    0x00000003
    0x00000002
    low0x00000001
    (栈顶)

    在没有字节对齐的情况下,变量a就是占用了0x00000001这一个字节,而变量b则是占用了0x00000002~0x000000005这四个字节,那么cpu如果想从内存中读取变量b,首先要从变量b的开始地址0x00000002读到0x0000004,然后再读取一次0x00000005这个字节,相当于读一个int,cpu从内存读取了两次。

    而如果进行字节对齐的话,变量a还是占用了0x00000001这一个字节,而变量b则是占用了0x00000005~0x00000008这四个字节,那么cpu要读取变量b的话,就直接一次性从0x00000005读到0x00000008,就一次全部读取出来了。

    所以说,字节对齐的根本原因其实在于cpu读取内存的效率问题,对齐以后,cpu读取内存的效率会更快。但是这里有个问题,就是对齐的时候0x00000002~0x00000004这三个字节是浪费的,所以字节对齐实际上也有那么点以空间换时间的意思,具体写代码的时候怎么选择,其实是看个人的。

    3.手动设置对齐

    什么情况下需要手动设置对齐:

    • 设计不同CPU下的通信协议,比如两台服务器之间进行网络通信,共用一个结构体时,需要手动设置对齐规则,确保两边结构体长度一直;
    • 编写硬件驱动程序时寄存器的结构;

    手动设置对齐方式有两种:

    • 代码里添加预编译标识:
    //用法如下
    #pragma pack(n)//表示它后面的代码都按照n个字节对齐
    struct st3
    {
        char a;
        int b;
    };
    #pragma pack()//取消按照n个字节对齐,是对#pragma pack(n)的一个反向操作
    //这里计算sizeof(st3)=5

    上面这两行其实就类似于开车的时候,走到某一段路的时候,发现一个限速60公里的指示牌,过了那一段路以后,又会有解除限速60公里的指示牌。

    • 定义结构体时:
    //用法如下
    struct bbb
    {
       char a;
       int b;
    }__attribute__((packed));//直接按照实际占用字节来对齐,其实就是相当于按照1个字节对齐了
    //这里计算sizeof(st3)=5

    4.结构体比较方法

    可以使用内存比较函数memcpy进行结构体比较,但因为结构体对齐可能会有填充位不一致的情况,此时需要注意:

    1. 设置为1个字节对齐,使它没有空位;
    2. 事先对结构体进行初始化;
    memcpy(char *dest, const char* src, int len); //头文件#include<string.h>
    展开全文
  • 本文就C语言字节对齐的问题进行详细的解析,感性趣的朋友可以看看。
  • C语言中,结构是一种复合数据类型,其构成元素既可以是基本数据类型(如int、long、float等)的变量,也可以是一些复合数据类型(如数组、结构、联合等)的数据单元。
  • C语言字节对齐详解

    2021-05-19 09:23:36
    先了解4个基本概念:1、数据类型自身对齐值:即数据类型的大小(数组取数组成员类型的自身对齐值),如char的自身对齐值是1,short是2,int、float、double都是4,单位字节2、结构体的自身对齐值:结构体成员中自身...

    先了解4个基本概念:

    1、数据类型自身对齐值:即数据类型的大小(数组取数组成员类型的自身对齐值),如char的自身对齐值是1,short是2,int、float、double都是4,单位字节

    2、结构体的自身对齐值:结构体成员中自身对齐值最大的那个值

    3、指定对齐值:使用#pragma pack (value)时指定的对齐值alue

    4、有效对齐值:自身对齐值和指定对齐值中较小的那个值

    其次,数据存放必须满足以下两个法则:

    法则1:有效对齐值为N的数据在内存中存放的起始地址必须是N的整数倍,即满足“存放起始地址 # N = 0”

    法则2:结构体的变量占用的总长度必须是结构体有效对齐值的整数倍

    有了以上基础,就能判断一个结构体占用内存的空间大小,下面举几个例子分析:

    struct B

    {

    char b;

    int a;

    short c;

    }

    假设B从0x0000开始存放,并且默认编译环境默认的指定对齐值是4。第一个成员变量b的自身对齐值是1,比指定对齐值4小,所以有效对齐值是1,所以存放在0x0000空间。第二个成员a的自身对齐值是4,指定对齐值亦是4,所以有效对齐值是4,其存放起始气质必须是4的整数倍,所以必须存放在0x0004~0x0007空间。第三个成员c的自身对齐值是2,比指定对齐值4小,所以有效对齐值是2,紧接a占用空间的下一个起始地址0x0008满足2的整数倍,所以存放在0x0008~0x0009空间。最后,B的自身对齐值是具有最大自身对齐值的成员变量a的自身对齐值4,等于指定对齐值4,所以B总共占用0x0000~0x0011空间。

    0818b9ca8b590ca3270a3433284dd417.png

    #pragma pack (2);

    struct C

    {

    char b:

    int a;

    short c:

    };

    虽然结构体C的成员组成和结构体B的成员完全一致,但由于定义结构体前指定了对齐值为2,所以所有自身对齐值大于2的成员变量的有效对齐值都变成了2,而且结构体的最终有效对齐值也变成了2,所以占用空间比B小,如下图:

    0818b9ca8b590ca3270a3433284dd417.png

    对于联合union,遵循的原则也是一样的,只不过union最终的长度是仅按照占用空间最大的那个成员来计算的,如

    union   D{

    char   a;   //自身对齐值1

    int   b[5];    //自身对齐值4,占用空间最大为5×4 = 20

    double   c;  //自身对齐值8

    int   d[3];   //自身对齐值4

    };

    按占用空间最大的成员长度计算,该union初步的长度的20字节,而所有成员中自身对齐值最大的是c,为8,所以该union长度要圆整到8的整数倍,即最终长度是24字节

    在编程的时候,为减少中间的填补空间,基本原则是把结构体中的变量按照自身对齐值从小到大排列

    展开全文
  • C语言字节对齐

    2021-05-21 10:24:06
    什么是字节对齐?现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据按照...
  • 结构体的字节对齐,在笔试中经常考到,这里从下面三段代码简单的总结一下结构体字节对齐的计算方式。 计算的时候需要遵循一个原则,即每个变量的其实地址应该为它长度的整数倍。 struct Data{ int a; char b; ...
  • C语言字节对齐4

    2021-05-19 07:53:56
    字节对齐类型的字节对齐规则我们可以使用“__packed”、“__attribute__((packed))”、“#pragma”等方式控制结构体的字节对齐,这些结构体的内部结构在定义时就已经确定了,当它们被包含在其它结构体内部时它们被...
  • C语言字节对齐 对于标准数据类型,它的地址只要是它的长度的整数倍就行了,而非标准数据类型按下面的原则对齐: 数组 :按照基本数据类型对齐,第一个对齐了后面的自然也就对齐了。 联合 :按其包含的长度最大的数据...
  • 一 什么是字节对齐 现代计算机中,内存空间按照字节划分,理论上可以从任何起始地址访问任意类型的变量。但实际中在访问特定类型变量时经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列...
  • C语言字节对齐[归类].pdf
  • 前言字节对齐是我们初学 C语言 就会接触到的一个概念,但是到底什么是字节对齐?对齐准则又是什么?为什么要字节对齐呢?字节对齐对我们编程有什么启示?本文将简单理一理字节对齐的那些事。什么是字节对齐计算机中...
  • C语言字节对齐__align()讲解[整理].pdf
  • 一、概念   对齐跟数据在内存中的位置有关。... 需要字节对齐的根本原因在于CPU访问数据的效率问题。假设上面整型变量的地址不是自然对齐,比如为0x00000002,则CPU如果取它的值的话需要访问两次内存,第...
  • C语言字节对齐笔记

    2019-05-09 15:29:49
    ** 一、字节对齐的意义**: 通过合理的内存对齐可以提高访问效率,有效地节省存储空间,为使CPU能够对数据进行快速访问,数据的起始地址应具有“对齐”特性。比如4字节数据的起始地址应位于4字节边界上,即起始地址...
  • 一文搞懂c语言字节对齐 如果你对c语言的字节对齐总感觉模糊,不能从理论上推导出一个复杂结构体实际占用的内存大小,那么你必须要看看本博文,硬干货!!! 测试环境是ubutun 64位 文章目录基本概念自身对齐默认对齐...
  • 一、概念     对齐跟数据在内存中的位置有关。如果一个变量的内存地址... 需要字节对齐的根本原因在于CPU访问数据的效率问题。假设上面整型变量的地址不是自然对齐,比如为0x00000002,则CPU如果取它的值的话...
  • C语言字节对齐64位和32位

    千次阅读 2018-07-05 10:05:21
    (第一次写博客:有不对的地方还望指出)借前辈们的话再详细补充linux64位下字节对齐: 对齐:在GNU GCC 编译器中,遵循的准则:根据最宽的基本数据类型来定:对齐模数最大只能是4,也就是说,即使结构体中有double...
  • C语言字节对齐

    2021-01-19 09:37:29
    一、基本概念 1. 什么是自然对齐 对于一个存储在内存中的变量,如果它的内存...例子:以32位的CPU为例,32位的CPU,默认是4字节[32 / 8 = 4]对齐。 当整型数据A的存储起始地址为0x2,则它在内存中的数据占据了4..
  • 默认32位OS对齐字节是4,64位对齐字节是8。'N'有可能影响结构体内部成员的对齐位置,以及结构体整体大小。 gcc 中,N不能大于默认的对齐字节数,否则不生效。 对齐规则  规则一.:每个成员变量在其结构体内的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 38,477
精华内容 15,390
关键字:

c语言字节对齐

友情链接: hanconvert0.9.zip