C.13:结构体构成·结构体内存对齐·位段·枚举·联合

本文详细介绍了C语言中的结构体,包括结构体的构成、匿名结构体、结构体的意义、引用及类型重定义。同时,讲解了结构体内存对齐的规则,并探讨了位段的特性,强调位段的不可移植性和不确定性。此外,还提到了枚举和联合(共同体)的概念,揭示了它们在内存使用上的特点。
摘要由CSDN通过智能技术生成

一. 初识结构体

1. 结构体的构成

结构体关键字+结构体标签
{
    结构体成员
} 结构体变量(可不写);
                          //结构体关键字+结构体标签{结构体成员} 叫结构体类型
                          //创建结构体变量有2种方法:一种是创建结构体类型时创建变量(左上角形式)
                          //另一种是结构体创建好后用 结构体关键字+结构体标签+要创建的结构体变量 
                          //形式来创建

2. 匿名结构体:隐藏结构体标签

结构体关键字
{
    结构体成员
} 结构体变量(必须写);

//这种结构体也就只能以左边形式创建变量,这也意味着靠 结构体关键字+结构体标签+要创建的结构体变量
//形式创建变量是不可以的,因为没有结构体标签,如果该种结构体你只想用一次,那么使用匿名结构体比较合适

3. 结构体的意义解读

struct
{
    int a;
    char b;
    float c;

} a[20],*p        //数组a中有20个元素,每个元素都是一个结构体;
                  //p是一个指针,存放的是结构体的地址;

4. 结构体的引用:引用一个结构体要做的事情是获取这个结构体的地址

struct Node
{
    int data;
    struct Node* next;//存放要引用的结构体的地址
};

5. 结构体类型的重定义

typedef struct Node
{
    int data;
    struct Node* next;
} Node;
                            //这段代码的意思为:把结构体 struct Node{int data;struct Node*                                                                 
                           //next;}重新取一个名字,取名为Node,这意味着本来创建结构体变量时要
                          //用struct Node N,此时可以简写为:Node N,两者是等价的

                           
                         //匿名结构体没办法重定义

6. 结构体指针的重定义

typedef struct Node
{
    int data;
    struct Node* next;
} * pNode;
                        //这段代码的意思为:把结构体指针 typedef struct Node{int data;struct         
                       //Node* next;} *  重新取名为 pNode,这意味着本来创建结构体指针要用     
                      //struct Node *p,此为可以简写为 pNode p,两者是等价的

二. 结构体内存对齐

   对齐规则:1)第一个成员放在偏移量为0的地址处
            2)其他成员对齐到对齐数的整数倍数
            3)结构体的总大小为最大对齐数的整数倍
            4)如果嵌套了结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的总体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍




//备注:1)中 偏移量:一个字节相对于起始位置隔了几个字节偏移量就是几,很显然,起始位置偏移量为0;
       2)中 对齐数:编译器默认对齐数(vs默认为8)与组成员大小的较小数;
       3)中 最大对齐数:每个成员对齐数选出来进行比较,选出最大的,把它当作最大对齐数;
        offsetof(结构体关键字+标签,结构体成员名)是用来计算相对于起始位置的偏移量,返回的是无符号整型;
        设计结构体时,让占用空间小的成员尽量集中在一起;
        修改默认对齐数的方法:
                    #pragma pack(想填的整数)(此句后默认对齐数被修改成 想填的整数)
                                     .........
                    #pragma pack()(此句后对齐数被修改为默认值)
        

三. 位段:以位为单位来定义结构体中的成员变量所占的空间

1)位段的成员必须是 int,unsigned int 或 signed int
2)位段的成员名后面有一个冒号和一个数字:
    int _a : 2; // 开辟一个整型空间,把这个整型空间的2位空间给_a,剩下的空间分配给后面的变量,后面的变量也不一定就是紧紧挨着变量_a放的,反正最终肯定是节省了空间


注意:
        位段是不对齐的,因为位段本身是节省空间的;
        位段设及很多不确定因素,位段是不跨平台的,注重可移植的程序因避免使用位段;
        位段被当成有符号数还是无符号数是不确定的;
        位段中最大位数的数目不能确定(有的平台是16位一个int,有的平台是32位一个int);
        位段中的成员在内存中是从左向右分配还是从右向左分配尚未定义;
        当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段的剩余空间时,是舍弃剩余的位段还是利用,这是不确定的,即上例中所说的 “后面的变量也不一定就是紧紧挨着变量_a放的,反正最终肯定是节省了空间”.

四. 枚举

枚举结构形式:

enum col
{
    Red = 1,
    Green = 5,
    Blue = 9
};
                        //Red = 1为初始化,不是赋值,此后Red = 2是不行的,因为此时是赋值

五. 联合(又叫共同体):共同体指共用同一块内存区域,所以对于联合体内的成员,一般同一时间只会使用一个

共同体:共同体指共用同一块内存区域,所以对于联合体内的成员,一般同一时间只会使用一个





说明:共用同一块内存区域 是指从开始位置共用,即共同体内成员起始位置一样;
     联合体的关键字是 union,如:
                                        union Un
                                        {
                                            char arr[5];
                                            int i;
                                        };
    联合的成员是共用同一块内存空间的,这样一个联合成员的大小,至少是最大成员的大小,因为联合至少有能力保存最大的那个成员,当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍;
    联合体大小的计算:需要对齐计算:以上面的例子为例,“char arr[5]; ”,5个char类型,char大小为1,vs默认对齐数为8,所以最终对齐数为1,偏移量为0处开始放5个char,“int i;”,int大小为4,vs默认对齐数为8,所以最终对齐数为4,共同体共用他同一块内存(起始位置相同),所以偏移量为0处开始取4个字节放,最终arr[5]与i一共占用5个字节空间,5不是最大对齐数4(1与4比较得出)的整数倍,所以最终联合的空间为8个字节。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值