社区编辑申请
注册/登录
STM32编程中枚举和结构体的结合
开发 前端
结构体,通俗讲就像是打包封装,把一些有共同特征(比如同属于某一类事物的属性,往往是某种业务相关属性的聚合)的变量封装在内部,通过一定方法访问修改内部变量。

01 结构体定义

基本定义:结构体,通俗讲就像是打包封装,把一些有共同特征(比如同属于某一类事物的属性,往往是某种业务相关属性的聚合)的变量封装在内部,通过一定方法访问修改内部变量。

结构体的定义:

第一种:只有结构体定义

  1. struct stuff{   
  2.   char *name;  //姓名 
  3.   int num;  //学号 
  4.   int age;  //年龄 
  5.   float score;  //成绩 
  6. }; 

第二种:附加该结构体类型的“结构体变量”的初始化的结构体定义,如下代码也就是定义结构体时,直接定义一个变量

  1. struct stuff{   
  2.   char *name;  //姓名 
  3.   int num;  //学号 
  4.   int age;  //年龄 
  5.   float score;  //成绩 
  6. }xiaoming; 

其实这就相当于先定义结构体,再用结构体定义一个结构体变量:

  1. struct stuff{   
  2.   char *name;  //姓名 
  3.   int num;  //学号 
  4.   int age;  //年龄 
  5.   float score;  //成绩  
  6. };   
  7. struct stuff xiaoming;   

第三种:使用typedef关键字,可以将结构体变量定义时少写一个struct,比较省事。

  1. typedef struct stuff{   
  2.   char *name;  //姓名 
  3.   int num;  //学号 
  4.   int age;  //年龄 
  5.   float score;  //成绩  
  6. }stuff_s;   
  7. stuff_s xiaoming; 

使用typedef还可以进一步简化,将结构体名也省略,这也是常用的方式

  1. typedef struct{   
  2.   char *name;  //姓名 
  3.   int num;  //学号 
  4.   int age;  //年龄 
  5.   float score;  //成绩  
  6. }stuff_s;   
  7. stuff_s xiaoming; 

STM32的标准外设库有大量这样的应用,如下

  1. typedef struct 
  2.   uint32_t GPIO_Pin; 
  3.   GPIOMode_TypeDef GPIO_Mode; 
  4.   GPIOSpeed_TypeDef GPIO_Speed; 
  5.   GPIOOType_TypeDef GPIO_OType; 
  6.   GPIOPuPd_TypeDef GPIO_PuPd; 
  7. }GPIO_InitTypeDef; 

关于结构体指针定义问题,有很多的“骚操作”的写法,我一般按照下面定义指针

  1. stuff_s *cuerrent_student; 

02 结构体初始化

在大部分应用中,一般都是定义结构体后,在代码中进行初始化,如下所示

  1. typedef struct{   
  2.   char *name;  //姓名 
  3.   int num;  //学号 
  4.   int age;  //年龄 
  5.   float score;  //成绩  
  6. }stuff_s; 
  7. stuff_s xiaoming; 
  8. void xiaoming_inf_init() 
  9.   xiaoming.name = "xiaoming"
  10.   xiaoming.num = 1; 
  11.   xiaoming.age = 18.0; 
  12.   xiaoming.score = 100; 

当然也有可以定义时就进行数据初始化的

  1. typedef struct{   
  2.   char *name;  //姓名 
  3.   int num;  //学号 
  4.   int age;  //年龄 
  5.   float score;  //成绩  
  6. }stuff_s; 
  7. stuff_s xiaoming={"xiaoming",1,18.0,100}; 

C99和C11为结构提供了指定初始化器(designatedinitializer)。其初始化器使用点运算符和成员名。

关于C99和C11的知识可以看我之前的文章《C语言的发展》,在IAR和Keil中记得勾选C99的选项。

例如,只初始化xiaoming结构中的name成员,可以这样做:

  1. stuff_s xiaoming= 
  2.   .name = "xiaoming" 
  3. }; 

也可以按照任意顺序使用指定初始化器:

  1. stuff_s xiaoming= 
  2.   .age = 18.0, 
  3.   .name = "xiaoming" 
  4. }; 

这样的赋值方式,在linux方式中很常见,以platform驱动框架为例:

  1. static struct platform_driver leds_platform_driver = { 
  2.   .driver = { 
  3.     .name = "imx6ul-led"
  4.     .of_match_table = leds_of_match, 
  5.   }, 
  6.   .probe = leds_probe, 
  7.   .remove = leds_remove, 
  8. }; 

03 访问结构体成员

结构体成员的访问需要借助结构体成员运算符(.),如下

  1. stuff_s xiaoming,xiaohong; 
  2. void student_inf_init() 
  3.   xiaoming.name = "xiaoming"
  4.   xiaoming.num = 1; 
  5.   xiaoming.age = 18.0; 
  6.   xiaoming.score = 100; 
  7.    
  8.    
  9.   xiaohong.name = "xiaohong"
  10.   xiaohong.num = xiaoming.num+1; 

使用指针时,使用(->)符号访问结构体成员

  1. stuff_s xiaoming,xiaohong; 
  2. stuff_s *cuerrent_student; 
  3. void student_inf_init() 
  4.   xiaoming.name = "xiaoming"
  5.   xiaoming.num = 1; 
  6.   xiaoming.age = 18.0; 
  7.   xiaoming.score = 100; 
  8.   cuerrent_student = &xiaohong; 
  9.    
  10.    
  11.   cuerrent_student->name = "xiaohong"
  12.   cuerrent_student->num = xiaoming.num+1; 

04 枚举与结构体的结合

简单介绍下枚举:有些数据的取值往往是有限的,只能是非常少量的整数,并且最好为每个值都取一个名字,以方便在后续代码中使用,比如一个星期只有七天,一年只有十二个月,一个班每周有六门课程等。

当然,你可以用宏定义

  1. #define Mon 1 
  2. #define Tues 2 
  3. #define Wed 3 
  4. #define Thurs 4 
  5. #define Fri 5 
  6. #define Sat 6 
  7. #define Sun 7 

如果用了枚举则如下

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

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

  1. enum week a, b, c; 

那么枚举和结构体一起用会产生什么效果呢?假设我们要协议一个语音芯片的驱动,需要表示语音芯片的状态

  1. typedef enum//语音芯片状态 
  2.     VOICE_INIT_OK =            0x4A,  //语音芯片上电初始化成功后,自动回传命令 
  3.     VOICE_RECEIVE_OK =           0x41,  //语音芯片收到正确的命令帧 
  4.     VOICE_ORDER_ERROR=         0x45,  //语音收到错误的命令帧 
  5.     VOICE_BUSY     =            0x4E,  //语音忙(正在合成状态) 
  6.     VOICE_FREE     =           0x4F  //语音空闲 
  7. } VOICE_STATUS; 
  8. typedef struct { 
  9.     VOICE_STATUS status ;                 //!< 语音芯片状态 
  10.     Ouint32  delayTicks;                   //!< 播放时间 
  11.     Ouint32  playtimes;                    //!< 播放次数 
  12. } voicechip_Para_S; 
  13. voicechip_Para_S voicechip_Para; 

那么改变语音芯片状态时,我们可以按照下面这样写

  1. voicechip_Para.status = VOICE_RECEIVE_OK; 

判断语音芯片状态时,我们可以按照下面写

  1. if((voicechip_Para.status == VOICE_FREE) 

当然,你用宏定义是可以的,代码也很整洁。这里希望你能理解文章最开始的那句话:结构体是某种业务相关属性的聚合。

05 骚操作

关于结构体有很多骚操作,如果全部总结下来,这篇文章就会很臃肿,例如结构体嵌套的骚操作,可以一边定义结构体B,一边就使用上:

  1. struct A{   
  2.     struct B{   
  3. int c;   
  4.     }b;   
  5.     struct B sb;   
  6. }a; 

对于这样的情况,我一般主张能看懂就行,自己写代码时就少点这样的骚操作

  1. struct B{   
  2.      int c;   
  3. }b; 
  4. struct A{   
  5.      struct B sb;   
  6. }a; 

 

责任编辑:姜华 来源: 知晓编程
相关推荐

2011-04-11 13:00:08

C++结构体枚举

2009-08-18 09:37:14

C#枚举类型

2010-02-03 10:05:48

C++ enum枚举

2011-12-26 15:58:01

枚举

2009-08-18 13:00:59

C#枚举类型

2009-08-18 10:35:46

C#枚举类型

2009-08-18 13:06:17

2009-08-18 11:07:06

C#枚举类型

2009-08-18 10:59:46

C#枚举类型

2010-02-01 16:22:56

2010-02-01 16:40:14

同话题下的热门内容

字节的前端监控 SDK 是怎样设计的TestOps完全手册:工作流、生命周期、团队和流程使用Python快速搭建接口自动化测试脚本实战总结不要在 Python 中使用循环,这些方法其实更棒!哪种编程语言最适合开发网页抓取工具?从 Islands Architecture 看前端有多卷反应式JavaScript:前端架构的演变什么是WebAssembly?

编辑推荐

太厉害了,终于有人能把TCP/IP协议讲的明明白白了!牛人5次面试腾讯不成功的经验HBase原理–所有Region切分的细节都在这里了Javascript如何监听页面刷新和关闭事件如何搭建一个HTTPS服务端
我收藏的内容
点赞
收藏

51CTO技术栈公众号