(超详解)--->自定义类型(结构体,枚举,联合)

目录

本章学习重点:

        1:结构体类型的声明与变量的定义

        2:如何求解结构体的大小(结构体的内存对齐)

        3:结构体传参,结构体实现位段

        4:枚举类型的定义和优点

        5:联合的定义与特点及大小的计算


1:结构体类型的声明与变量的定义

        结构:结构是一些集合,这些值指的是成员变量。结构体的成员变量可以是不同类型的变量。

        结构的声明-->

        

 tag:是可以自己起名字。

member_list:结构体的成员变量的类型声明。

variable_list:结构体变量可以在此定义。

如果将tag去掉的话,那么此结构体是一个特殊的声明也称结构体的不完全声明,定义变量的时候只能在variable-list此处定义。‘

struct tag才叫结构体的定义类型。

 如果定义两个匿名结构体类型的话,尽管他们的成员变量相同但是编译器会认为他们的类型不同的。所以此时如果用结构体指针指向另外一个结构体是非法的 。

  结构体的自引用:即结构体里面包含指向自身结构的指针。

        不能是结构体的原因:假设是结构体里面包含结构体,则会形成无限套娃的形式sizeof(结构体)的大小就不能够计算出来了。

结构体变量的定义与初始化

结构体变量的定义可以分为两种情况下定义:

                1:在结构体声明的时候定义变量与进行初始化.s1,s2

        2:在用类型加变量名定义的时候初始化。s3,s

      2:求解结构体的大小(结构体的内存对齐)

        首先我们来了解结构体的对齐规则:

                1:结构体的第一个成员在结构体偏移量为0的地址处,即结构体的起始位置开始处。

                2:其他成员变量对齐到某个对齐数的整数倍地址处。

                        对齐数=结构体成员本身的大小与编译器默认的对齐数的较小值

                3:结构体的最终大小最大对齐数(每个成员变量对齐数的最大值)的整数倍

                4:如果包含结构体嵌套,那么嵌套的结构体对齐到自身最大对齐数的整数倍地址处,结构体的整体大小就是所有最大对齐数(含嵌套结构体)的整数倍处。

           练习:

        

struct S1
{
 char c1;
 int i;
 char c2;
};

printf("%d\n", sizeof(struct S1));

     图解:

解释:首先我们先将c1变量放在偏移量为0的地址处,大小为1个字节。

        i的大小为4个字节而vs默认对齐数为8,所以对齐数为4,所以我们的结构体就会浪费3个字节的空间使i偏移到地址为4处开始

        c2变变量自身大小为1,对齐数为1所以c2变量直接在i后1个字节的空间就行。

        现在的大小为9个字节,根据第三条规则,结构体的大小为最大对齐数的整数倍,而此处大小为4,所以还要浪费三个字节的空间,所以最终答案为12. 

为啥会存在结构体内存对齐呢?

        平台原因:不是所有的硬件平台都够访问任意地址上的任意处的数据,如果访问的话则会抛出硬件异常。

        性能原因:数据结构(尤其是栈),如果内存未对齐那么我们的处理器需要两次内存访问,而对齐了的话则只需要一次访问就行

    总的来说:结构体内存对齐就是拿空间来换时间

为了即提高空间的效率与时间的效率,避免浪费太多的空间,我们可能会使成员变量小的尽可能放在一起  

我们可以使用 #pragma pack()   来改变平台默认对齐数

3:结构体传参与位段

结构体传参的时候可以传结构体,也可以传地址,那么我们应该选哪个呢?

        一般我们都会选择传地址,这是因为形式参数会在内存中进行压栈等操作,会浪费一定的时间与空间,如果结构体足够大,那么形式参数所需要的时间与空间的消耗更大,导致性能的下降。

        结论:结构体传参的时候传地址

位段:

        其实位段也是在结构体的基础上进行的操作,只是说它的语法不完全相同如:

        

struct s
{
    int a:4;
    int b:5;
    int c:6;
    //位段的成员名后边有一个冒号和一个数字
    //位段成员的类型必须为整形家族的
    
};

        这些后面的数字单位都是字节

位段开辟空间的时候一般是按照4个字节的空间开辟或者是按照1个字节的空间开辟

当既有整形又有字符型的时候一般都是按照整形进行开辟空间的

4:枚举的定义与优点

        定义:涉及一个关键字enum,生活中有些事物是可以一一列举出来的,枚举就是将所有可能一一列举出来的,比如说一周有多少天,三原色,性别...

        

在enum{}当中的成员,又可以叫做枚举常量,且他们的值是依次递增1的,当然也可以给他们赋值。其中enum sex称作枚举类型

 优点:

        与#define相比,   1.枚举可以增加代码的可读性和可维护性

                                      2.与#define相比枚举定义的常量有类型检查,更加严谨

                                       3.便于调试

                                       4.使用方便1次可以定义多个常量

只能拿枚举常量给枚举变量赋值。其他类型的常量会error

5:共用体的定义与特点及大小的计算

共用体:一般用union来定义比如:

union Un

{
 char c;
 int i;
};

特点:是共用体共用同一块内存空间,也就是说共用体的大小最小为成员变量类型的最大值

共用体的计算:

联合的大小至少是最大成员的大小。

当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。

                        感谢大家的观看!

猜你喜欢

转载自blog.csdn.net/2201_75964502/article/details/131715181