美文网首页
嵌入式第十天:结构

嵌入式第十天:结构

作者: 水枂 | 来源:发表于2019-10-15 23:00 被阅读0次

    今天来说一下C语言里的结构体(struct)、共用体(l联合体)union、枚举。
    欢迎加入嵌入式学习群:559601187

    (一)结构体:struct

    1.1 概念

    • 是一种自定义的数据类型
    • 结构体是构造类型的一种
    • 不同数据类型的集合
    • 地址空间连续,每次分配最大数据类型的宽度
    • 占用内存为所有变量的总大小(注意字节对齐问题)

    1.2 定义

    1.先定义结构体类型,再说明结构体变量

    struct stu
    {
        char *name;  //姓名
        int num;  //学号
        int age;  //年龄
        float score;  //成绩
    };
    struct stu  student;
    

    上面的程序使用strcuct关键字定义了一个结构体名为stu的结构体类型。和定义变量一样,声明一个结构体类型变量可以使用:数据类型 变量名 的形式。
    struct stu student表示定义了一个变量名为stduent,类型为stu的结构体。该结构体含有4个成员:name、num、age、score
    注意大括号后面的分号;不能少,这是一条完整的语句。
    2.定义结构体类型的同时定义结构体变量

    struct stu
    {
        char *name;  //姓名
        int num;  //学号
        int age;  //年龄
        float score;  //成绩
    }student;
    

    在定义时直接声明结构体变量,只需要将结构体变量名放在花括号后面,并加上分号即可。
    3.直接说明结构体变量

    struct 
    {
        char *name;  //姓名
        int num;  //学号
        int age;  //年龄
        float score;  //成绩
    } student;
    

    这种定义方式并不常用,这样做书写虽然简单,但是因为没有结构体名,后面就没法用该结构体定义新的变量。
    4.typedef重定义

    typedef struct 
    {
        char *name;  //姓名
        int num;  //学号
        int age;  //年龄
        float score;  //成绩
    } STU;
    STU student;
    

    这种方式比较常见,我们使用typedef重定义结构体为STU,这里STU就是此结构体类型,可以用STU去定义结构体变量

    1.3 初始化

    1.在定义结构体变量的时候全部初始化

    struct stu
    {
        char *name;  //姓名
        int num;  //学号
        int age;  //年龄
        float score;  //成绩
    }student={“ha”,1234,56,99};
    

    2.定义完结构体变量后,之后只能单个赋值

    struct stu
    {
        char *name;  //姓名
        int num;  //学号
        int age;  //年龄
        float score;  //成绩
    };
    struct stu  student;
    student.name="ha";
    student.num=1234;
    student.age=56;
    student.score=99;
    

    1.4 调用

    结构体变量.成员
    

    结构体变量名+点('.')+成员就可以调用了

    1.5 结构体指针

    当一个指针变量指向结构体时,我们就称它为结构体指针。C语言结构体指针的定义形式一般为:

    struct 结构体名 *变量名;
    
    //结构体
    struct stu{
        char *name;  //姓名
        int num;  //学号
        int age;  //年龄
        float score;  //成绩
    } stu1 = { "hah", 12, 18, 23, 136.5 };
    //结构体指针
    struct stu *pstu = &stu1;
    

    注意结构体变量名和数组名不同,数组名在表达式中会被转换为数组指针,而结构体变量名不会,无论在任何表达式中它表示的都是整个集合本身,要想取得结构体变量的地址,必须在前面加&,所以给 pstu 赋值只能写作:

    1.6 获取结构体成员

    通过结构体指针可以获取结构体成员,一般形式为:

    (*pointer).memberName
    

    或者:

    pointer->memberName
    

    第一种写法中,.的优先级高于,(pointer)两边的括号不能少。如果去掉括号写作pointer.memberName,那么就等效于(pointer.memberName),这样意义就完全不对了。

    第二种写法中,->是一个新的运算符,习惯称它为“箭头”,有了它,可以通过结构体指针直接取得结构体成员;这也是->在C语言中的唯一用途。

    1.7 结构体内存分析

    注意点

    1. 给整个结构体变量分配储存空间和数组一样,从内存地址比较大的开始分配
    2. 给结构体变量中的属性分配储存空间也和数组一样,从所占内存地址比较小的开始分配
    3. 定义结构体类型不会分配储存空间,只有定义结构体变量的时候才会分配储存空间
    • 结构体在分配内存的时候,会做一个内存对齐的操作
    • 会先获取所有属性中占用内存最大的属性的字节数
    • 然后在开辟出最大属性字节的内存给第一个属性,如果分配给第一个属性之后还能继续分配给第二个属性,那么就继续分配给第二个属性
    • 如果分配给第一个属性之后,剩余的内存不够分配给第二个属性了,那么会再次开辟最大属性的内存,再次分配 依次类推
    #include <stdio.h>
    
    int main(){
    
        //定义结构体
        struct Person
         {
            char name; // 1 个节点  //开辟4个字节 char 占用1个
            int age;  // 4个字节   // 剩余三个 不够int  再开辟4个字节
            int money; // 4个字节 // 再开辟4个字节
        };
    
        struct Person p; // 所以p = 4+4+4
    
        printf("sizeof(p) = %i\n",sizeof(p)); // 12个字节
        return 0;
    }
    

    (二)共用体(联合体):union

    2.1概念

    • 所有变量共用一段空间
    • 每次分配按最大长度进行分配
    • 是一种构造数据类型
    • 同一时刻只能保存一个成员的值
    • 不能直接引用共用体变量名

    2.2定义

    它的定义和结构体一样,分为先定义共用体再说明共用体变量、在定义共用体的同时说明共用体变量、直接说明共用体变量

    union 共用体名{
        成员列表
    };
    

    示例:

    //先定义共用体再说明共用体变量
    union data{
        int n;
        char ch;
        double f;
    };
    union data a, b, c;
    

    2.3 引用

    和结构体一样,通过共用体变量名 . 成员名

    union data{
        int n;
        char ch;
        double f;
    } a, b, c;
    a.n=3;
    

    关于共用体的详细介绍可以看下这篇文章C语言共用体(C语言union用法)详解,讲到共用体这里要说明一下大小端模式的问题。

    大小端
    小端模式:低地址存放低字节,高地址存放高字节
    大端模式:低地址存放高字节,高地址存放低字节

    (三)枚举:enum

    3.1 概念

    • 作用:列举出所有的可能性,增强代码的可阅读性
    • 枚举成员都是常量
    • 不能再对已经定义好的枚举常量赋值

    3.1 定义

    enum 枚举名 
    {
    枚举变量
    };
    

    示例:

    enum week
    { 
    Mon, Tues, Wed, Thurs, Fri, Sat, Sun
     };
    typedef enum
    {
    Mon, Tues, Wed, Thurs, Fri, Sat, Sun
    }Date;
    
    

    枚举是一种类型,通过它可以定义枚举变量:

    Date a,b,c
    

    我们也可以给每个名字都指定一个值:

    enum week{ Mon = 1, Tues = 2, Wed = 3, Thurs = 4, Fri = 5, Sat = 6, Sun = 7 };
    

    更为简单的方法是只给第一个名字指定值:

    enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun };
    

    这样枚举值就从 1 开始递增,跟上面的写法是等效的。
    也可以在定义枚举类型的同时定义变量:

    enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } a, b, c;
    

    有了枚举变量,就可以把列表中的值赋给它:

    enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun };
    enum week a = Mon, b = Wed, c = Sat;
    

    或者:

    enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } a = Mon, b = Wed, c = Sat;
    

    特点:可以在定义枚举时给成员赋值,被赋值的成员往后依次增加1,也可以在中间改变某一个成员的值。

    3.1 引用

    直接使用就行,需要注意的是**枚举列表中的数据作用范围是全局的,不能在定义与它们名字相同的白能量;Mon、Tues、Wed 等都是常量,不能对它们赋值,只能将它们的值赋给其他的变量。
    示例:

    #include <stdio.h>
    int main(){
        enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } day;
        scanf("%d", &day);
        switch(day){
            case 1: puts("Monday"); break;
            case 2: puts("Tuesday"); break;
            case 3: puts("Wednesday"); break;
            case 4: puts("Thursday"); break;
            case 5: puts("Friday"); break;
            case 6: puts("Saturday"); break;
            case 7: puts("Sunday"); break;
            default: puts("Error!");
        }
        return 0;
    }
    

    Mon、Tues、Wed 这些名字都被替换成了对应的数字。这意味着,Mon、Tues、Wed 等都不是变量,它们不占用数据区(常量区、全局数据区、栈区和堆区)的内存,而是直接被编译到命令里面,放到代码区,所以不能用&取得它们的地址。这就是枚举的本质。


    本文章仅供学习交流用禁止用作商业用途,文中内容来水枂编辑,如需转载请告知,谢谢合作

    微信公众号:zhjj0729

    微博:文艺to青年

    相关文章

      网友评论

          本文标题:嵌入式第十天:结构

          本文链接:https://www.haomeiwen.com/subject/btiemctx.html