结构体struct与内存对齐

目录

一、结构体

定义

使用

1.成员变量的范围

2.结构体嵌套

二、内存对齐

如何理解字节对齐问题:

如何计算结构体的大小?

指令对齐符

二、结构体指针

定义

使用

成员访问


一、结构体

定义

        struct类型名
        {
                (成员列表\属性)
                成员1;
                成员2;
                .....
        };  //重点是:需要哪些信息

   eg:

        struct Student
        {
                char name[20];
                int age;
        };//定义完成,其作用和内置类型一样,类型的设计不占用内存空间

使用

1.成员变量的范围

        通过类型来定义变量,再对变量内的数据按照定义顺序依次初始化

  • 结构体数组:
    •         eg:struct Studeng arr[]={{},{}...};
  • 访问:
    •         arr[i].name,arr++
  • 成员访问:
    •         变量名称.结构体变量   ‘.’成员访问符
      •         eg:student.name

例如:

        struct Student student = {"李四",14};

        struct Student student1;//如果是局部变量(写在函数内部)->未初始化,成员内容为随机值,编译会报错;如果是全局变量(写在函数外部)->未初始化,编译器给成员列表默认值初始化int,short那些都是0,char类型为\0,编译不会报错

例题求解:

            struct Student a;//利用struct Student数据类型定义一个变量a;

            struct Student b = { "曹操",20};

            b.age = 21;//结构体的普通变量通过“.”访问其成员

            (1)修改b的名字为刘备

            错误:b.name=”刘备”//不允许字符串赋值给数组,应该用循环,跟结构体没关系

            正确:strcpy(b.name, "刘备"); 

            (2)输出b的数据:名字和年龄

            printf(" % s, % d", b.name, b.age);

            (3)将a改为“孙权”,18

            strcpy(a.name, "孙权");

                a.age = 18;

简化使用:

        1.struct类型名

          { }别名;

        2.typedef struct 类型名 别名;

2.结构体嵌套

结构体内可以使用之前声明过的结构体类型

eg:

        struct Date
        {
                int year;
                int month;
                int day;
        }Date;

        struct Student
        {
                const char* name;
                int age;
                Date birthday;

        };

        int main()
        {
                struct Student s1 = {"李四",14,{2001.9.18}};
        }

二、内存对齐

如何理解字节对齐问题:

  1. 内存的基本单位是字节,理论上来说,可以任意地址访问变量,但实际上CPU并不是逐个字节的进行内存读取,而是以2,4,8的倍数的字节块来读写内存,因此对基本数据类型的地址做出了限制,那么就要求各种数据类型按照一定的规则在空间上排列。
  2. 有些平台每次都是从偶地址开始,而如果存放在奇地址开始的地方,就需要2个都读周期,并对两次读出的结果高低字节进行拼凑才能得到该32bit数据。显然在读取效率上下降很多。
  3. 由于不同平台对齐方式可能不同。如此一来,同样的结构在不同的平台其大小可能不同,在无意识的情况下,互相发送的数据可能出现错乱,甚至引发严重的问题。

如何计算结构体的大小?

记住做法通过补齐的方式,让当前变量即上面所有的大小加起来是当前变量大小的倍数,而且要满足最后的结果与结构体内变量最大字节对其。

注意1:当数组不是第一个成员是就要注意,要进行单个字节对其,而不是看整个数组的大小。

2:有嵌套struct时,大小不是按照整个struct计算,也是单独每个变量的类型。

特殊情况:在嵌套结构体时,如果是无名的strcut(既无变量名又无参数名),此时计算情况与上述的一般情况一致,如果是无参数名的struct A,则sizeof(A)=0;

添加:

 #pragma pack(1)

是以1对其,其实就是不按照内存对其,有多少字节就是多少。

内存对齐理论原理:

1.结构体变量地址的首地址,必须是结构体变量中的“最大基本数据类型成员所占字节数”的整数倍。

  如下为例:

 //eg:
struct Student
{
    char name[20]; //1*20=20字节
    int age; //4字节
};

        因为20为结构体内最大字节,所以结构体变量首地址必须是20的倍数。如图

       ->倍数为0

2.结构体变量中的每个成员相对于结构体首地址的偏移量,都是该成员基本数据类型所占字节的整数倍。

3.结构体变量的总大小,为结构体变量中“最大基本数据类型成员所占字节数”的整数(注意:struct和数组都不是基本数据类型)

举例分析:

将如图字节在内存中分配

(1)

解:char cha:1字节,char chb:1字节,int ia:4字节,最起码要在4的位置放,因此浪费两个字节。1+1+2+4=8是4的倍数,因此结构体的字节大小为8

(2)

 解:cha:1,da:8需要前面浪费7个字节,chb:1。8+8+1=17。最小24。

(3)

解:ch:3,ia:4,前面浪费一个,4+4=8,是4的倍数,则为8。

(4)嵌套结构体分析:

解:10+8+12=30,4*8=32浪费2个字节。

32+8=40,基本数据类型为double:8字节,40是8的倍数,结构体字节大小为40。

(5)数组分析要小心:

  在该结构体内,数组short b[4]=8字节,short:2字节,char a=1字节,那么a是应该+1还是+7?实际应该是+1,因为,char a+1占用2个字节后,short本身就是2字节,从第2后面开始也合理。int c:4字节,最后结果为:2+8+4=14,4*4=16。因此,最小16字节

(6)

        char a=1,d=8,char a在对对齐时+7还是+3?如果+3,char a占用4个字节内存大小,int:4字节,float:4字节,也是可以的。因此结果为1+3+8=12。

(7)

 1+3+4+2=10,不是最大字节4的倍数,因此要在+2,最后结果为:12

(8)特殊情况需要记忆:

因为结构体sizeof(II)=0,它只定义了类型,没有变量名(在“};”处没有写东西),变量大小就是0,类型本身不占大小。1+3+0+4=8。=》8

(9)​​​​​​​​​​​​​​​​​​​​​

 struct是无名变量,虽然也没有写变量名,但是可以这么使用,此时的情况就和一般的情况一样

1+3+4+4+4=16

(10)嵌套联合体

联合体union kk大小,sizeof(union kk)=4,1+3+4+4=12。

  • 写代码时检验可以通过printf(“%d”,sizeof(struct A));输出检查。   

指令对齐符

预处理指令#pragma pack(n),可以改变默认对其数,n的取值为1,2,4,8,16。

如果#pramga pack(n)中的n大于结构体成员中任何一个成员所占用的字节数,则该n值无效。编译器会选取结构体中最大数据成员的字节数为基准进行对其

eg:字节对其数为2,a读取1次,浪费1个空间,b读取两次,c读取1次,浪费1个空间。

 字节对其数为4,a读取1次,浪费3个空间,b读取1次,c读取1次,浪费3个空间。

二、结构体指针

定义

        typedef struct Student* stu;

        或者

        struct Student

        {

                char name[20];

                int age;

        }*stu;

使用

        通过类型来定义指针变量,再对其赋与指向。

        eg:

        Student s1 = { "张三",20 };

        typedef struct Student* stu;

        stu S=&s1;

        通过S输出s1的内容。

        eg:

        printf(“%c,%d”,S->name,S->age);

成员访问

1.(*变量名称).结构体变量  ‘.’成员访问符

(*S).age; 必须有括号,因为“.”的优先级高于“*”

2.变量名称->结构体变量    ‘->’指向符

S->age;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值