精华内容
下载资源
问答
  • C语言结构体字节对齐

    2020-03-21 18:44:35
    C语言结构体字节对齐 C语言结构体字节对齐 在学习C语言的过程中,可能永远的只使用变量来做操作,在一些特殊的情况下需要存储更多的内容的时候,比如我们在学习c语言时的练习题,做一个仓库管理系统或者学生信息...

    C语言结构体字节对齐

    在学习C语言的过程中,不可能永远的只使用变量来做操作,在一些特殊的情况下需要存储更多的内容的时候,比如我们在学习c语言时的练习题,做一个仓库管理系统或者学生信息管理系统这种东西的时候,就会使用到结构体,可能在初学的时候在pc上不会去考虑过多的字节对齐的问题。因为我们的内存还是比较多,够用的。
    但是工作中会尽可能的裁剪你的系统,裁剪你的硬件,做到能省就省,毕竟针对大批量的产品来说,一件产品能省下一毛钱硬件,大批量就可以节省不少成本,从而带来更多的利润。不多扯题外话,讲下字节对齐的内容,工作中可能会用到,但是面试中避免不了的。之前的另外一篇博客中有说过使用memcmp去比较结构体是否相等的问题。今天就从最简单的开始讲起。
    C语言中有个sizeof关键字,其作用是用来计算得到某种数据类型所占用的内存空间大小。其用法直接上代码,直观,下文的前提是所有代码基于32位操作系统。64位同理,linux某发行版本查看系统信息:

    # uname -a
    Linux linux-xv9p 3.11.6-4-desktop #1 SMP PREEMPT Wed Oct 30 18:04:56 UTC 2013 (e6d4a27) i686 i686 i386 GNU/Linux
    
    #include <stdio.h>
    
    int main(int argc, char **argv)
    {
        printf("sizeof(int) = %d\n", sizeof(int));
        printf("sizeof(char) = %d\n", sizeof(char));
        printf("sizeof(short) = %d\n", sizeof(short));
        printf("sizeof(long) = %d\n", sizeof(long));
        printf("sizeof(float) = %d\n", sizeof(float));
        printf("sizeof(double) = %d\n", sizeof(double));
        printf("sizeof(long long) = %d\n", sizeof(long long));
    
        return 0;
    }
    

    编译运行结果如下:
    在这里插入图片描述
    上面是直接针对数据的修饰类型进行求sizeof的,如果我们有一个数据类型的变量,直接求这个变量所占的内存空间也是可以的。我们修改一下代码,例如:

    #include <stdio.h>
    
    int main(int argc, char **argv)
    {
    /*
        printf("sizeof(int) = %d\n", sizeof(int));
        printf("sizeof(char) = %d\n", sizeof(char));
        printf("sizeof(short) = %d\n", sizeof(short));
        printf("sizeof(long) = %d\n", sizeof(long));
        printf("sizeof(float) = %d\n", sizeof(float));
        printf("sizeof(double) = %d\n", sizeof(double));
        printf("sizeof(long long) = %d\n", sizeof(long long));
    */
    
        int a = 5;
        int b[5] = {0};
        
        printf("sizeof(a) = %d\n", sizeof(a));
        printf("sizeof(b[5]) = %d\n", sizeof(b));
    
        return 0;
    }
    

    猜一下结果是多少,sizeof(a), a是int型修饰,所以sizeof(a)就等于sizeof(int),那sizeof(b)呢?b也是int型修饰,但是他是一个数组啊,数组怎么可能和同类型的一个单变量占同样大小的内存空间呢?这不合理是不是。分析一下b[5]的定义,int b[5];那b的类型是不是可以理解成int [5] b;假设这是种新类型来修饰一个变量b。合理,那sizeof(b)就等于sizeof(int*5)。来验证一下:
    在这里插入图片描述
    结论是成立的。这就是sizeof的用法,然后就有一种求指针的sizeof(),指针是什么。最通俗的理解就是指针是存储目标的地址的一个变量。32位机器中就是有32条总线,既然是32位,那必然是需要32bit来表示所有总线,也就是需要4byte空间大小才能表示完这32条总线,所以32位机器中所有指针的sizeof都是4,同理64位机器中所有指针的sizeof都是8。那么这32条总线能访问到的最大内存就是 0-2^32 = 4096MByte=4GByte,也就是32位操作系统最多就只能访问4G的内存,加内存也没啥用,升级操作系统吧。那2^64就不知道大到哪里去了。所以64位机器就可以疯狂加内存,只要你的主板没有限制就ok。话题岔开了,回来。
    有了上面的求变量的内存空间占用,实际工作中我们还是会遇到很多结构体的处理。如下一个结构体:

    struct Test
    {
    	int a;
    	char b;
    };
    

    该结构体里面有两个成员变量,一个整型的a,另外一个字符型的b。那么sizeof(struct Test)=?那计算一下,sizeof(int)+sizeof(char) = 5。理论上这样计算是没错的。但是在内存访问的时候可能会花比较多的时间去找到这个变量,这个具体的细节暂时还没有太深入的研究,操作系统以及编译器在编译时就采取一种牺牲空间换时间的操作,去默认结构体对齐,以便于寻址更迅速,毕竟运行速度快比牺牲点内存更令人容易接受,毕竟内存一般都是有富余的。那编译器是怎么对齐的。32位机器下其实是默认按照4字节对齐的,因为总线的缘故,4字节对齐更容易寻址,64位机器对齐方式暂未研究,可能会比32位机器复杂的多。何为4字节对齐呢。如上面的结构体来说,先验证一下sizeof等于多少:

    #include <stdio.h>
    
    typedef struct Test
    {
        int a;
        char b;
    }test;
    
    int main(int argc, char **argv)
    {
    /*
        printf("sizeof(int) = %d\n", sizeof(int));
        printf("sizeof(char) = %d\n", sizeof(char));
        printf("sizeof(short) = %d\n", sizeof(short));
        printf("sizeof(long) = %d\n", sizeof(long));
        printf("sizeof(float) = %d\n", sizeof(float));
        printf("sizeof(double) = %d\n", sizeof(double));
        printf("sizeof(long long) = %d\n", sizeof(long long));
    
        int a = 5;
        int b[5] = {0};
    
        printf("sizeof(a) = %d\n", sizeof(a));
        printf("sizeof(b[5]) = %d\n", sizeof(b));
    */
        printf("suzeof(test) = %d\n", sizeof(test));
        return 0;
    }
    

    在这里插入图片描述
    所以这个结构体占用了8个字节,但是成员变量实际只占用了5个字节,那多余的三个字节去哪了?
    测试一下,怎么测试呢,把这个八个字节依次取出来,看看那些是我们赋值过去的,哪些是随机的,就可以知道这个结构体的内存分布方式了。上代码,注释比较详细,不展开讲代码了:

    #include <stdio.h>
    
    typedef struct Test
    {
        int a;
        char b;
    }test;
    
    int main(int argc, char **argv)
    {
    /*
        printf("sizeof(int) = %d\n", sizeof(int));
        printf("sizeof(char) = %d\n", sizeof(char));
        printf("sizeof(short) = %d\n", sizeof(short));
        printf("sizeof(long) = %d\n", sizeof(long));
        printf("sizeof(float) = %d\n", sizeof(float));
        printf("sizeof(double) = %d\n", sizeof(double));
        printf("sizeof(long long) = %d\n", sizeof(long long));
    
        int a = 5;
        int b[5] = {0};
    
        printf("sizeof(a) = %d\n", sizeof(a));
        printf("sizeof(b[5]) = %d\n", sizeof(b));
    */
        printf("suzeof(test) = %d\n", sizeof(test));
        char i = 0, tmp[8] = {0};
        test ts = {0x01020304,0x05};    //对结构体赋值,ts.a=0x01020304, ts.b=0x05;
        char *ptr = (char *)&ts.a;      //使用字符指针指向结构体的首地址
        for(i = 0; i < 8; i++)
        {
            tmp[i] = *ptr++;        //依次将结构体的每个字节赋值给数组tmp
        }
        for(i = 0; i < 8; i++)
        {
            printf("%d\t", tmp[i]);     //将数组的每个值打印出来,就相当于将结构体的每个字节打印出来
        }
        printf("\n");
    
        return 0;
    }
    

    编译运行结果:
    在这里插入图片描述
    所以可以看出这个结构体的成员分布了。
    在这里插入图片描述
    低地址存放低字节数据,同时也可以说明我这台机器是小端模式。所以在这个结构体上,char b占用了四个字节,但是有效字节只有1个,后面三个都是为了对齐填充上去的。这就是字节对齐。那如果这个结构体变了呢?

    struct test
    {
    	int a;
    	char b;
    	short c;
    };
    

    会是怎样的情况呢?可以用同样的方法去测试,改下代码:

    #include <stdio.h>
    
    typedef struct Test
    {
        int a;
        char b;
        short c;
    }test;
    
    int main(int argc, char **argv)
    {
    /*
        printf("sizeof(int) = %d\n", sizeof(int));
        printf("sizeof(char) = %d\n", sizeof(char));
        printf("sizeof(short) = %d\n", sizeof(short));
        printf("sizeof(long) = %d\n", sizeof(long));
        printf("sizeof(float) = %d\n", sizeof(float));
        printf("sizeof(double) = %d\n", sizeof(double));
        printf("sizeof(long long) = %d\n", sizeof(long long));
    
        int a = 5;
        int b[5] = {0};
    
        printf("sizeof(a) = %d\n", sizeof(a));
        printf("sizeof(b[5]) = %d\n", sizeof(b));
    */
        printf("suzeof(test) = %d\n", sizeof(test));
        char i = 0, tmp[8] = {0};
        test ts = {0x01020304, 0x05, 0x0607};    //对结构体赋值,ts.a=0x01020304, ts.b=0x05, ts.c=0x0607
        char *ptr = (char *)&ts.a;      //使用字符指针指向结构体的首地址
        for(i = 0; i < 8; i++)
        {
            tmp[i] = *ptr++;        //依次将结构体的每个字节赋值给数组tmp
        }
        for(i = 0; i < 8; i++)
        {
            printf("%d\t", tmp[i]);     //将数组的每个值打印出来,就相当于将结构体的每个字节打印出来
        }
        printf("\n");
    
        return 0;
    }
    

    因为我知道这个结构体还是占8个字节,所以循环这里我没该,如果自己测试没把握的情况下不要这么随意测试,会出现段错误的,编译看结果:
    在这里插入图片描述
    所以short是在char 后面的空余的三个字节中取了两个自己,因为本身只有两个字节,距下一个四字节对齐还空余三个字节,所以完全够用,为啥是后面的两个字节呢,因为寻址偶数更快寻址。结构图不进一步画了。
    再改一下:

    struct test
    {
    	int a;
    	char b;
    	int c;
    };
    

    按照猜想是不是就占用12个字节了,因为char空余的三个字节不够用的了char独占4个字节,测试:

    #include <stdio.h>
    
    typedef struct Test
    {
        int a;
        char b;
        int c;
    }test;
    
    int main(int argc, char **argv)
    {
    /*
        printf("sizeof(int) = %d\n", sizeof(int));
        printf("sizeof(char) = %d\n", sizeof(char));
        printf("sizeof(short) = %d\n", sizeof(short));
        printf("sizeof(long) = %d\n", sizeof(long));
        printf("sizeof(float) = %d\n", sizeof(float));
        printf("sizeof(double) = %d\n", sizeof(double));
        printf("sizeof(long long) = %d\n", sizeof(long long));
    
        int a = 5;
        int b[5] = {0};
    
        printf("sizeof(a) = %d\n", sizeof(a));
        printf("sizeof(b[5]) = %d\n", sizeof(b));
    */
        printf("suzeof(test) = %d\n", sizeof(test));
        char i = 0, tmp[64] = {0};
        test ts = {0x01020304, 0x05, 0x06070809};    //对结构体赋值,ts.a=0x01020304, ts.b=0x05, ts.c=0x0607
        char *ptr = (char *)&ts.a;      //使用字符指针指向结构体的首地址
        for(i = 0; i < sizeof(test); i++)
        {
            tmp[i] = *ptr++;        //依次将结构体的每个字节赋值给数组tmp
        }
        for(i = 0; i < sizeof(test); i++)
        {
            printf("%d\t", tmp[i]);     //将数组的每个值打印出来,就相当于将结构体的每个字节打印出来
        }
        printf("\n");
    
        return 0;
    }
    

    编译执行:
    在这里插入图片描述
    结果与猜想一致。
    所以以后工作中如果内存很紧张的情况下针对结构体的优化可以从字节对齐入手,一般是采用小字节成员变量在前,大字节成员变量在后的这种规则进行分配,减少内存的占用,同时减少废弃数据。以上总结,linux下结构体的字节对齐遵循与操作系统版本一致的4字节对齐方式,在数据空间足够的情况下会存在公用四字节的情况。还有更多的对齐方式不展开讲。强制对齐见另外一篇博客:https://blog.csdn.net/weixin_34153142/article/details/104759932
    以上如有错误还请指出,感谢!

    展开全文
  • 这就牵扯到结构体中字节对齐的概念。 (什么叫字节对齐结构体是一种构造数据类型,里面可以有不同的数据类型的成员,在这些数据成员中,不同的数据类型所占的内存空间是不同的,那么这些成员是...

    首先我们来看一个结构体
    例题1

    struct STUDENT
    {
    char a;
    int b;
    }data;
    

    如上结构体占多少个字节呢?
    思考:char占一个字节,int占四个字节,所以总共占5个字节吗?
    其实不是。这就牵扯到结构体中字节对齐的概念。
    (什么叫字节对齐?结构体是一种构造数据类型,里面可以有不同的数据类型的成员,在这些数据成员中,不同的数据类型所占的内存空间是不同的,那么这些成员是怎么存储的呢?其实就是按字节对齐方式存储的,即以结构体成员中占内存最多的数据类型所占的字节数为标准,所有的成员在分配内存时,都要与这个长度对齐)
    正如上面这个例子:char占一个字节,int占四个字节,与4字节的长度对齐,也就是说,虽然char是一个字节,但是为了与4字节的长度对齐,所以其后面的3字节都会空着(但空并不是什么都没有就同定义了一个变量没有初始化一样)。
    在这里插入图片描述
    所以data不是占5个字节,而是占8个字节。
    又如三个成员对齐:
    例题2:

      struct STUDENT
            {
            char a;
            char b;
            int c;
            }data;
    

    在这里插入图片描述
    char a占一个字节,b占一个字节,b接着a后面填充
    此时data 仍占8个字节。
    由上思考:下面结构体占几个字节呢??
    例题3:

     struct STUDENT
            {
            char a;
            int b;
            char c;
            
            }data;
    

    在这里插入图片描述
    首先最长类型所占字节数为 4,所以是以 4 对齐。分配内存的时候 a 占 1 字节,然后 b 想紧接着 a 后面存储,但 a 后面还剩 3 字节,小于 b 的 4 字节,所以 b 另起一行分配。然后 c 想紧接着 b 后面分配,但是 b 后面没空了,所以 c 另起一行分配。所以总共 12 字节。

    总结:同样三个数据类型,只不过交换了一下位置,结构体变量data所占的内存空间就由8字节变成12字节,多了4字节。这就告诉我们,在声明结构体类型时,各类型成员的前后位置会对该结构体类型定义的结构体变量所占的字节数产生影响。没有规律的定义会增加系统给结构体变量分配的字节数,降低内存分配的效率。但这种影响对操作系统来说几乎是可以忽略不计的!

    又如多个成员对齐:

    例题4:

    struct STUDENT
            {
            char a;
            char b;
            char c;
            char d;
            chae e;
            int f;
            }data;
    

    在这里插入图片描述

    首先最长的数据类型占 4 字节,所以是以 4 对齐。然后 a 占 1 字节,b 接在 a 后面占 1 字节,c 接在 b 后面占 1 字节,d 接在 c 后面占 1 字节,此时满 4 字节了,e 再来就要另起一行。f 想紧接着 e 后面分配,但 e 后面还剩 3 字节,小于 int 类型的 4 字节,所以 f 另起一行。总共占12个字节。
    又如当出现数组怎样对齐:
    例题5:

    struct STUDENT
    {
        char name[10];
        int age;
        char sex;
        float score;
    }data;
    

    结构体变量 data 中成员最长类型占 4 字节,还是以 4 对齐。所以总共占24个字节。

    在这里插入图片描述

    展开全文
  • C语言结构体对齐原则 Q:关于结构体的对齐,到底遵循什么原则? A:首先先讨论结构体按多少字节对齐,先看看只以1字节对齐的情况: #include #include #define PRINT_D(intValue) printf(#int...

    C语言结构体的对齐原则

    Q:关于结构体的对齐,到底遵循什么原则?

    A:首先先不讨论结构体按多少字节对齐,先看看只以1字节对齐的情况:

    #include <stdio.h>
    #include <string.h>
    
    #define PRINT_D(intValue)     printf(#intValue" is %d\n", (intValue));
    #define OFFSET(struct,member)  ((char *)&((struct *)0)->member - (char *)0)
    
    #pragma pack(1)
    
    typedef struct
    {
        char    sex;
        short   score;
        int     age;
    }student;
    
    int main()
    {
        PRINT_D(sizeof(student))
        PRINT_D(OFFSET(student,sex))
        PRINT_D(OFFSET(student,score))
        PRINT_D(OFFSET(student,age))
        return 0;
    }

    输出:
    sizeof(student) is 7
    OFFSET(student,sex) is 0
    OFFSET(student,score) is 1
    OFFSET(student,age) is 3
    可以看到,如果按1字节对齐,那么结构体内部的成员紧密排列,sizeof(char) == 1, sizeof(short) == 2, sizeof(int) == 4.

    修改上面的代码, 去掉#pragma pack语句,代码如下:

    #include <stdio.h>
    #include <string.h>
    
    #define PRINT_D(intValue)     printf(#intValue" is %d\n", (intValue));
    #define OFFSET(struct,member)  ((char *)&((struct *)0)->member - (char *)0)
    
    typedef struct
    {
        char    sex;
        short   score;
        int     age;
    }student;
    
    int main()
    {
        PRINT_D(sizeof(student))
        PRINT_D(OFFSET(student,sex))
        PRINT_D(OFFSET(student,score))
        PRINT_D(OFFSET(student,age))
        return 0;
    }

    运行结果:
    sizeof(student) is 8
    OFFSET(student,sex) is 0
    OFFSET(student,score) is 2
    OFFSET(student,age) is 4

    此时,各个成员之间就不像之前那样紧密排列了,而是有一些缝隙。这里需要介绍下对齐原则:

    此原则是在没有#pragma pack语句作用时的原则(不同平台可能会有不同):

    原则A:struct或者union的成员,第一个成员在偏移0的位置,之后的每个成员的起始位置必须是当前成员大小的整数倍;

    原则B:如果结构体A含有结构体成员B,那么B的起始位置必须是B中最大元素大小整数倍地址;

    原则C:结构体的总大小,必须是内部最大成员的整数倍;

    依据上面3个原则,我们来具体分析下: sex在偏移0处,占1字节;score是short类型,占2字节,score必须以2的整数倍为起始位置,所以它的起始位置为2; age为int类型,大小为4字节,它必须以4的整数倍为起始位置,因为前面有sex占1字节,填充的1字节和score占2字节,地址4已经是4的整数倍,所以age的位置为4.最后,总大小为4的倍数,不用继续填充。

    继续修改上面的代码,增加#pragma pack语句:

    #include <stdio.h>
    #include <string.h>
    
    #define PRINT_D(intValue)     printf(#intValue" is %d\n", (intValue));
    #define OFFSET(struct, member)  ((char *)&((struct *)0)->member - (char *)0)
    
    #pragma pack(4)
    
    typedef struct
    {
        char    sex;
        short   score;
        int     age;
    }student;
    
    int main()
    {
        PRINT_D(sizeof(student))
        PRINT_D(OFFSET(student,sex))
        PRINT_D(OFFSET(student,score))
        PRINT_D(OFFSET(student,age))
        return 0;
    }

    运行结果:
    sizeof(student) is 8
    OFFSET(student,sex) is 0
    OFFSET(student,score) is 2
    OFFSET(student,age) is 4

    具体分析下:

    有了#pragma pack(4)语句后,之前说的原则A和C就不适用了。实际对齐原则是自身对齐值(成员sizeof大小)和指定对齐值(#pragma pack指定的对齐大小)的较小者。依次原则,sex依然偏移为0, 自身对齐值为1,指定对齐值为4,所以实际对齐为1; score成员自身对齐值为2,指定对齐值为4,实际对齐为2;所以前面的sex后面将填充一个1字节,然后是score的位置,它的偏移为2;age自身对齐值为4,指定对齐为4,所以实际对齐值为4;前面的sex和score正好占用4字节,所以age接着存放;它的偏移为4.

    Q:关于位域的问题,空域到底表示什么?
    A:它表示之后的位域从新空间开始。

    #include <stdio.h>
    #include <string.h>
    
    #define PRINT_D(intValue)     printf(#intValue" is %d\n", (intValue));
    #define OFFSET(struct, member)  ((char *)&((struct *)0)->member - (char *)0)
    
    typedef struct 
    {
        int a : 1;
        int b : 3;
        int : 0;
        int d : 2;
    }bit_info;
    
    int main()
    {
        PRINT_D(sizeof(bit_info))
        return 0;
    }
    运行结果:
    sizeof(bit_info) is 8
    bit_info中的a, b占用4个字节的前4位,到int:0; 时表示此时将填充余下所有没有填充的位,即刚刚的4个字节的余下28位;int d:2; 将从第四个字节开始填充,又会占用4个字节,所以总大小为8.


    展开全文
  • 作者:阿凡卢 ... 本文版权归作者和博客园共有,欢迎转载,但未经作者同意...C语言结构体对齐原则 Q:关于结构体的对齐,到底遵循什么原则? A:首先先讨论结构体按多少字节对齐,先看看只以1字节对齐的情况: ...

    作者:阿凡卢

    出处:http://www.cnblogs.com/luxiaoxun/

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

    为了免责!!!! 

     

     

    C语言结构体的对齐原则

    Q:关于结构体的对齐,到底遵循什么原则?
    A:首先先不讨论结构体按多少字节对齐,先看看只以1字节对齐的情况:

    复制代码

    #include <stdio.h>
    #include <string.h>
    
    #define PRINT_D(intValue)     printf(#intValue" is %d\n", (intValue));
    #define OFFSET(struct,member)  ((char *)&((struct *)0)->member - (char *)0)
    
    #pragma pack(1)
    
    typedef struct
    {
        char    sex;
        short   score;
        int     age;
    }student;
    
    int main()
    {
        PRINT_D(sizeof(student))
        PRINT_D(OFFSET(student,sex))
        PRINT_D(OFFSET(student,score))
        PRINT_D(OFFSET(student,age))
        return 0;
    }

    复制代码

    输出:
    sizeof(student) is 7
    OFFSET(student,sex) is 0
    OFFSET(student,score) is 1
    OFFSET(student,age) is 3
    可以看到,如果按1字节对齐,那么结构体内部的成员紧密排列,sizeof(char) == 1, sizeof(short) == 2, sizeof(int) == 4.

    修改上面的代码, 去掉#pragma pack语句,代码如下:

    复制代码

    #include <stdio.h>
    #include <string.h>
    
    #define PRINT_D(intValue)     printf(#intValue" is %d\n", (intValue));
    #define OFFSET(struct,member)  ((char *)&((struct *)0)->member - (char *)0)
    
    typedef struct
    {
        char    sex;
        short   score;
        int     age;
    }student;
    
    int main()
    {
        PRINT_D(sizeof(student))
        PRINT_D(OFFSET(student,sex))
        PRINT_D(OFFSET(student,score))
        PRINT_D(OFFSET(student,age))
        return 0;
    }

    复制代码

    运行结果:
    sizeof(student) is 8
    OFFSET(student,sex) is 0
    OFFSET(student,score) is 2
    OFFSET(student,age) is 4

    此时,各个成员之间就不像之前那样紧密排列了,而是有一些缝隙。这里需要介绍下对齐原则:

    此原则是在没有#pragma pack语句作用时的原则(不同平台可能会有不同):

    原则A:struct或者union的成员,第一个成员在偏移0的位置,之后的每个成员的起始位置必须是当前成员大小的整数倍;

    原则B:如果结构体A含有结构体成员B,那么B的起始位置必须是B中最大元素大小整数倍地址;

    原则C:结构体的总大小,必须是内部最大成员的整数倍;

    依据上面3个原则,我们来具体分析下: sex在偏移0处,占1字节;score是short类型,占2字节,score必须以2的整数倍为起始位置,所以它的起始位置为2; age为int类型,大小为4字节,它必须以4的整数倍为起始位置,因为前面有sex占1字节,填充的1字节和score占2字节,地址4已经是4的整数倍,所以age的位置为4.最后,总大小为4的倍数,不用继续填充。

    继续修改上面的代码,增加#pragma pack语句:

    复制代码

    #include <stdio.h>
    #include <string.h>
    
    #define PRINT_D(intValue)     printf(#intValue" is %d\n", (intValue));
    #define OFFSET(struct, member)  ((char *)&((struct *)0)->member - (char *)0)
    
    #pragma pack(4)
    
    typedef struct
    {
        char    sex;
        short   score;
        int     age;
    }student;
    
    int main()
    {
        PRINT_D(sizeof(student))
        PRINT_D(OFFSET(student,sex))
        PRINT_D(OFFSET(student,score))
        PRINT_D(OFFSET(student,age))
        return 0;
    }

    复制代码

    运行结果:
    sizeof(student) is 8
    OFFSET(student,sex) is 0
    OFFSET(student,score) is 2
    OFFSET(student,age) is 4

    具体分析下:

    有了#pragma pack(4)语句后,之前说的原则A和C就不适用了。实际对齐原则是自身对齐值(成员sizeof大小)和指定对齐值(#pragma pack指定的对齐大小)的较小者。依次原则,sex依然偏移为0, 自身对齐值为1,指定对齐值为4,所以实际对齐为1; score成员自身对齐值为2,指定对齐值为4,实际对齐为2;所以前面的sex后面将填充一个1字节,然后是score的位置,它的偏移为2;age自身对齐值为4,指定对齐为4,所以实际对齐值为4;前面的sex和score正好占用4字节,所以age接着存放;它的偏移为4.

    Q:关于位域的问题,空域到底表示什么?
    A:它表示之后的位域从新空间开始。

    复制代码

    #include <stdio.h>
    #include <string.h>
    
    #define PRINT_D(intValue)     printf(#intValue" is %d\n", (intValue));
    #define OFFSET(struct, member)  ((char *)&((struct *)0)->member - (char *)0)
    
    typedef struct 
    {
        int a : 1;
        int b : 3;
        int : 0;
        int d : 2;
    }bit_info;
    
    int main()
    {
        PRINT_D(sizeof(bit_info))
        return 0;
    }

    复制代码

    运行结果:
    sizeof(bit_info) is 8
    bit_info中的a, b占用4个字节的前4位,到int:0; 时表示此时将填充余下所有没有填充的位,即刚刚的4个字节的余下28位;int d:2; 将从第四个字节开始填充,又会占用4个字节,所以总大小为8.

     

    作者:阿凡卢

    出处:http://www.cnblogs.com/luxiaoxun/

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

    展开全文
  • 对于 一个 结构 体的 字 节数 大家 有没 有遇 到 什么 疑问 呢 先看 一个 结构 体 typedef struct Test { char a1; int a2; char a3; short a4; }Test_T; 在 32 位 编 译 系 统 下 这 一 个 结 构 体 的 字 节 数 是...
  • 字节对齐的原因: 1)平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据,某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常 2)硬件原因:经过内存对齐之后,CPU的内存...
  • C语言结构体对齐也是老生常谈的话题了。基本上是面试题的必考题。内容虽然很基础,但一小心就会弄错。写出一个struct,然后sizeof,你会不会经常对结果感到奇怪?sizeof的结果往往都比你声明的变量总长度要大,这...
  • C语言结构体内存对齐

    2015-11-04 14:31:31
    对齐概述 对齐的规则 计算步骤 对比 小结 对齐概述 1.性能原因:为了提高cup的效率访问...对齐的规则参考 结构体对齐问题 说实话,规则看起来太好理解,直接模仿下面步骤即可计算步骤以32位机器为例,工具为vs2008
  • c语言结构体内存对齐

    2017-05-15 15:40:14
    比如有些架构的CPU在访问一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐,其他平台可能没有这种情况,但是最常见的是如果按照适合其平台要求对数据存放进行对齐,会在存取效率上...
  • 问题描述:在开发过程中,构建了一个结构体,然后将结构体保存到flash芯片中,读取出来的时候数据内容和存进去的一样(STM32F103芯片)问题所在:构建结构体的时候,没有注意到结构体数据的对齐问题,计算错了...
  • 结构体在内存中分配一块连续的内存,但结构体内的变量并一定是连续存放的,这涉及到内存对齐。原则1 数据成员对齐规则:结构(struct或联合union)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据...
  • 但是结构体的计算方式就和普通的数据类型一样。  在C语言里面字节对齐的方式主要根据“有效对齐数”来确定,那么有效对齐数是怎杨确定的呢?   在结构体里面::: 有效字节对齐数 = (自身对齐数 < 最大...
  • 最近找工作,被笔试给卡死了,很多基础都忘了,今天花了半天缕了下结构体内存对齐,整理下自己的心得,有哪里写错请指出。 我们直接例子说明: typedef struct TEST{ int a; char b[2]; double c; short d; double e...
  • 首先说说为什么要对齐。为了提高效率,计算机从内存中取数据是按照一个固定长度的。...如果不对齐,很不巧,这个int数据刚好跨越了取数的边界,这样就需要取两次才能把这个int的数据全部取到,这样
  • 但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐对齐的作用和原因:各个硬件平台对存储空间的...
  • 对于一个结构体的字节数大家有没有遇到什么疑问呢? 先看一个结构体: typedef struct Test { char a1; int a2;...因为编译器会对不足4字节的变量空间自动补齐为4个字节(这就是内存对齐),以提高CPU...
  • C语言结构体对齐

    2019-04-12 15:26:06
    解析C语言结构体对齐(内存对齐问题) C语言结构体对齐也是老生常谈的话题了。基本上是面试题的必考题。内容虽然很基础,但一小心就会弄错。写出一个struct,然后sizeof,你会不会经常对结果感到奇怪?sizeof的结果...
  • 除了C语言自身带数据类型,还有自定义的数据类型,比如:结构体、枚举、联合。指针、数组也可以看作自定义的数据类型。 结构体 结构的每个成员可以是不同类型的变量。 结构体和数组类似,可以整体初始化,但能...
  •  对齐跟数据在内存中的位置有关。如果一个变量的内存地址正好位于它长度的整数倍,他就被称做自然对齐。比如在32位cpu下,假设一个整型变量的地址为0x00000004,那它就是自然对齐的。    二、为什么要字节对齐  ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 474
精华内容 189
关键字:

c语言结构体不对齐

c语言 订阅