• 第1章 C语言高级的枚举、typedef、位域(三)


    文档配套视频讲解链接地址

    1. 腾讯课堂视频链接地址 : 06_自定义类型_枚举的理解
    2. 腾讯课堂视频链接地址 : 07_自定义类型_typedef关键字
    3. 腾讯课堂视频链接地址 : 08_自定义类型_位域理解

    1.3 枚举类型(enum)

    • 枚举是 C 语言中的一种基本数据类型,它可以让数据更简洁,更易读。

    • 枚举的初衷是为了替代宏的用法 。

    • 枚举语法定义格式为:

    enum 枚举名 {枚举元素1,枚举元素2,……};
    
    • 1
    • 例如:
    enum WEEK {Mon,Tue,Wed,Tur,Fri,Sat,Sun}; 
    
    • 1
    • 实例13

    • 源文件

    03-chigh/13-enum.c
    
    • 1
    • 源代码
    #include 
    enum WEEK
    {
        Mon,  //这里就是一个宏值  , 默认为0 , 默认这个值是一个整数
        Tue,  // 1
        Wed,  // 2
        Thu,  // 3
        Fri,  // 4
        Sat,  // 5
        Sun   // 6 
    };
    
    int main(int argc, char const *argv[])
    {
    
        enum WEEK day; // day 是一个整型变量 , 理解为 int day 
        for(day = Mon ; day <= Sun; day++)
        {
            printf("%d ",day); 
        }
        printf("\n");
        day = Thu ; 
        printf("Thu=%d\n",day); 
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 运行结果
    0 1 2 3 4 5 6 
    Thu=3
    
    • 1
    • 2
    • 实例14
    • 源文件
    03-chigh/14-enum.c
    
    • 1
    • 源代码
    #include 
    enum WEEK
    {
        Mon=1,  // 可以指定一个值, 
        Tue,  // 2
        Wed,  // 3
        Thu,  // 4
        Fri,  // 5
        Sat,  // 6
        Sun   // 7 
    };
    
    int main(int argc, char const *argv[])
    {
    
        enum WEEK day; // day 是一个整型变量 , 理解为 int day 
        for(day = Mon ; day <= Sun; day++)
        {
            printf("%d ",day); 
        }
        printf("\n");
    
        printf("Mon=%d\n",Mon); // 直接使用成员名, 因为成员名就是一个整型常量
        printf("Tue=%d\n",Tue); // 直接使用成员名, 因为成员名就是一个整型常量
        printf("Wed=%d\n",Wed); // 直接使用成员名, 因为成员名就是一个整型常量
        printf("Thu=%d\n",Thu); // 直接使用成员名, 因为成员名就是一个整型常量
        printf("Fri=%d\n",Fri); // 直接使用成员名, 因为成员名就是一个整型常量
        printf("Sat=%d\n",Sat); // 直接使用成员名, 因为成员名就是一个整型常量
        printf("Sun=%d\n",Sun); // 直接使用成员名, 因为成员名就是一个整型常量
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 运行结果
    1 2 3 4 5 6 7 
    Mon=1
    Tue=2
    Wed=3
    Thu=4
    Fri=5
    Sat=6
    Sun=7
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    枚举类型举例

    enum   // 省略枚举名 
    { GPIO_Mode_AIN = 0x0,   // 每一个成员都赋值一个值 
      GPIO_Mode_IN_FLOATING = 0x04,
      GPIO_Mode_IPD = 0x28,
      GPIO_Mode_IPU = 0x48,
      GPIO_Mode_Out_OD = 0x14,
      GPIO_Mode_Out_PP = 0x10,
      GPIO_Mode_AF_OD = 0x1C,
      GPIO_Mode_AF_PP = 0x18
    };
    
    enum   // 省略枚举名 
    { 
      GPIO_Speed_10MHz = 1,  // 第一个成员赋值为1 
      GPIO_Speed_2MHz,      // 2 
      GPIO_Speed_50MHz      // 3 
    };
    
    enum
    { Bit_RESET = 0,  // 0 
      Bit_SET         // 1 
    };
    
    
    
    enum 
    {
        RESET = 0,   // 0 
        SET = !RESET // 1
    };
    
    enum 
    {
        DISABLE = 0, 
        ENABLE = !DISABLE
    } ;
    
    enum 
    {
        ERROR = 0, 
        SUCCESS = !ERROR
    } ;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    1.4 typedef 关键字

    typedef这个关键字用来定义一个新的数据类型

    • 语法:
    typedef  原有的类型   新的类型  ;    // 给原有类型起一个别名
    
    • 1
    • typedef定义基础类型
    /* Convenience types.  */ 
    typedef unsigned char __u_char;    // 用给前面的类型起一个别名
    typedef unsigned short int __u_short;
    typedef unsigned int __u_int;
    typedef unsigned long int __u_long;
    
    /* exact-width signed integer types */
    typedef   signed          char int8_t;  // 由typedef 定义出来的别名
    typedef   signed short     int int16_t;
    typedef   signed           int int32_t;
    typedef   signed       __INT64 int64_t;
    
        /* exact-width unsigned integer types */
    typedef unsigned          char uint8_t;
    typedef unsigned short     int uint16_t;
    typedef unsigned           int uint32_t;
    typedef unsigned       __INT64 uint64_t;
    
    typedef uint32_t  u32;
    typedef uint16_t u16;
    typedef uint8_t  u8;
    
    typedef int32_t  s32;
    typedef int16_t s16;
    typedef int8_t  s8;
    
    
    
    //追溯一个定义:
    typedef __SIZE_TYPE__ size_t;  // size_t 是__SIZE_TYPE__的别名, 用size_t 表示__SIZE_TYPE__
    #define __SIZE_TYPE__ long unsigned int // 宏, 用__SIZE_TYPE__  表示long unsigned int
    size_t 就是一个 long unsigned int 类型 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • typedef定义结构体类型
    typedef struct
    {
      uint16_t GPIO_Pin;             /*!< Specifies the GPIO pins to be configured.
                                          This parameter can be any value of @ref GPIO_pins_define */
    
      GPIOSpeed_TypeDef GPIO_Speed;  /*!< Specifies the speed for the selected pins.
                                          This parameter can be a value of @ref GPIOSpeed_TypeDef */
    
      GPIOMode_TypeDef GPIO_Mode;    /*!< Specifies the operating mode for the selected pins.
                                          This parameter can be a value of @ref GPIOMode_TypeDef */
    }GPIO_InitTypeDef;
    
    // 结构体 struct {...} 的别名是GPIO_InitTypeDef , 可以使用GPIO_InitTypeDef类型来定义一个结构体变量
    
    // 用法如下: 
    GPIO_InitTypeDef GPIO_InitStruct ;
    
    // 宏 , 也叫标识常量  
    // #define  N  10 
    // #define GPIO_Pin_9                 ((uint16_t)0x0200)  /*!< Pin 9 selected */
    // #define GPIO_Pin_8                 ((uint16_t)0x0100)  /*!< Pin 8 selected */
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_8 ; //  指定PB9 PB8  初始化  
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz ; //  设置引脚最大速度5M  
    
    // 推挽输出, 因为要对外提供电流, 必须要启动PMOS,所以必须设置推挽
    GPIO_InitStruct.GPIO_Mode = 	GPIO_Mode_Out_PP ; 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • typedef定义枚举类型
    typedef enum
    { 
      GPIO_Speed_10MHz = 1, // 可以在程序中把这个枚举常量当成宏(标识常量)去使用 
      GPIO_Speed_2MHz,  // 2
      GPIO_Speed_50MHz  // 3
    }GPIOSpeed_TypeDef;
    
    // typedef {  ... } 这个结构体类型的别名是 GPIOSpeed_TypeDef
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • typedef 定义函数类型
    // func 是一个函数名
    // 也是一个函数的入口地址 
    // 也是函数的首地址
    int func(int a, int b);  // 这是函数声明
    
    // 加上typedef 后, func_t就不再是函数名了, 是一个函数类型 
    // 参数是(int , int )
    // 返回值 int 
    // 可是使用func_t 来定义一个函数指针
    typedef  int func_t(int a, int b) ; 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 实例15
    • 计算2个数的加减乘除
    • 源文件
    03-chigh/15-typedef.c
    
    • 1
    • 源代码
    #include 
    
    // func 是一个函数名
    // 也是一个函数的入口地址
    // 也是函数的首地址
    int func(int a, int b); //  这个是函数的声明
    
    // 加上typedef 后, func_t就不再是函数名了, 是一个函数类型
    // 参数是(int , int )
    // 返回值 int
    // 可是使用func_t 来定义一个函数指针
    typedef int func_t(int a, int b); // 这是一个新类型的定义 , 和定义结构体一样
    
    int add(int a, int b)
    {
        return a + b;
    }
    int sub(int a, int b)
    {
        return a - b;
    }
    int mul(int a, int b)
    {
        return a * b;
    }
    int div(int a, int b)
    {
        return a / b;
    }
    
    int main(int argc, char const *argv[])
    {
        func_t *pfunc; // 定义一个func_t类型的变量 , func_t 是一个函数类型的, 因此pfunc是一个函数指针变量
        pfunc = add;
        int ret = pfunc(10, 20);
        printf("ret=%d\n", ret);
    
        pfunc=sub; 
        ret = pfunc(10, 20);
        printf("ret=%d\n", ret);
    
        pfunc = mul ; 
        ret = pfunc(10, 20);
        printf("ret=%d\n", ret);
    
        pfunc = div; 
        ret = pfunc(10, 20);
        printf("ret=%d\n", ret);
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 运行结果
    ret=30
    ret=-10
    ret=200
    ret=0
    
    • 1
    • 2
    • 3
    • 4

    1.5 位域

    1. 位域的概念

    ​ 有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有 0 和 1 两种状态,用 1 位二进位即可。为了节省存储空间,并使处理简便,C 语言又提供了一种数据结构,称为"位域"或"位段"。

    ​ 所谓"位域"是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。

    典型的实例:

    • 用 1 位二进位存放一个开关量时,只有 0 和 1 两种状态。
    2. 位域的定义和位域变量的说明

    位域定义与结构定义相仿,其形式为:

    struct 位域结构名 
    {
    
     位域列表
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5

    其中位域列表的形式为:

    type [member_name] : width ;  //  数据类型  变量名称:暂用二进位的宽度 ; 
    
    • 1
    • 实例16
    • 源文件
    03-chigh/16-weiyu.c
    
    • 1
    • 源代码
    #include 
    
    typedef struct
    {
        unsigned int led1 : 1;   // led1 是一个开关量, 占用1个二进制的为 0和1
        unsigned int led2 : 1;   // led2 是一个开关量, 占用1个二进制的为 0和1
        unsigned int beep : 1;   // beep 是一个开关量, 占用1个二进制的为 0和1
        unsigned int keyval : 3; // keyval 按键的键值, 占用3个二进制的为 0,1,2,3,4,5,6,7
    } cmd_t;
    // 这个结构体的成员一共使用了 6个二进制的位, 结构体成员类型是unsigned int 是4个字节, 还剩下26个位没有使用
    
    
    int main(int argc, char const *argv[])
    {
        printf("sizeof(cmd_t)=%ld\n", sizeof(cmd_t));
        cmd_t cmd;    // 结构体定义了一个结构体变量
        cmd.led1 = 1; // led1 赋值为1
        cmd.led2 = 0; // led1 赋值为0
        cmd.beep = 1; // beep 赋值为1 
        cmd.keyval = 5; // keyval 赋值为5 
    
        printf("cmd.led1  =%d\n",cmd.led1); 
        printf("cmd.led2  =%d\n",cmd.led2); 
        printf("cmd.beep  =%d\n",cmd.beep); 
        printf("cmd.keyval=%d\n",cmd.keyval); 
    
    
        cmd.led1 = 10; // 提示溢出, 会产生逻辑问题 , 取最低位 1010 ,最低位0 
        cmd.led2 = 7; // 提示溢出, 会产生逻辑问题  , 取最低位 111 ,最低位1 
        cmd.beep = 2; // 提示溢出, 会产生逻辑问题  , 取最低位 10 ,最低位0 
        cmd.keyval = 10; // 提示溢出, 会产生逻辑问题 , , 取最低3位 1010 ,最低位010 
    
        printf("cmd.led1  =%d\n",cmd.led1); 
        printf("cmd.led2  =%d\n",cmd.led2); 
        printf("cmd.beep  =%d\n",cmd.beep); 
        printf("cmd.keyval=%d\n",cmd.keyval); 
    
    
    
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 运行结果
    16-weiyu.c: In function ‘main’:
    16-weiyu.c:27:16: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         cmd.led1 = 10; // led1 赋值为1
                    ^~
    16-weiyu.c:28:16: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         cmd.led2 = 7; // led1 赋值为0
                    ^
    16-weiyu.c:29:16: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         cmd.beep = 2; // beep 赋值为1
                    ^
    16-weiyu.c:30:18: warning: large integer implicitly truncated to unsigned type [-Woverflow]
         cmd.keyval = 10; // keyval 赋值为5
                      ^~
    sizeof(cmd_t)=4
    cmd.led1  =1
    cmd.led2  =0
    cmd.beep  =1
    cmd.keyval=5
    cmd.led1  =0
    cmd.led2  =1
    cmd.beep  =0
    cmd.keyval=2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 代码阅读
    typedef union
    {
      struct
      {
        uint32_t _reserved0:27;              /*!< bit:  0..26  Reserved */
        uint32_t Q:1;                        /*!< bit:     27  Saturation condition flag */
        uint32_t V:1;                        /*!< bit:     28  Overflow condition code flag */
        uint32_t C:1;                        /*!< bit:     29  Carry condition code flag */
        uint32_t Z:1;                        /*!< bit:     30  Zero condition code flag */
        uint32_t N:1;                        /*!< bit:     31  Negative condition code flag */
      } b;                                   /*!< Structure used for bit  access */
      uint32_t w;                            /*!< Type      used for word access */
    } APSR_Type;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
  • 相关阅读:
    Linux 中设置静态IP的方法步骤
    C++基本知识(二)---函数重载、引用、内联函数、auto关键字
    高数 |【2019数一真题】部分错题及经典题自用思路整理
    BI-SQL丨存储过程(一)
    高博基于stereo-imu的VO运行尝鲜
    debug技巧之远程调试
    学校网页设计成品 基于HTML+CSS+JavaScript仿山东财经大学官网 学校班级网页制作模板 校园网页设计成品
    【涨薪技术】0到1学会性能测试 —— LR录制回放&事务&检查点
    pytorch-05.用pytorch实现线性回归
    Jmeter插件duang duang duang 学会模拟各种场景
  • 原文地址:https://blog.csdn.net/shengli001842/article/details/127813956