近日在学习stm32的过程中遇到一些问题,特重新学习了一下C语言关于枚举、结构体、共用体类型的用法,现总结如下>>>
·C枚举类型
基本定义
首先,在谈enum的用法之前,要了解const的作用,我们知道const是一种定义常量的数据类型,即被定义的量不可改变数值 ,通常是用作为一些数值冠上一个名字,使得代码可读性更好,比如
const int true = 1;
const int false = 0;
switch(result)
{
case true: /* 写入对应函数*/
break;
case false: /*写入对应函数*/
break;
}
或者也可以用宏定义来给常量取名字,但此时常量并没有数据类型,关于const定义与#define宏定义详细的区别,可戳此处https://blog.youkuaiyun.com/just_mccc/article/details/108251183
#define true 1
#define false 0
而如果需要定义的常量数量大且种类繁多,就会显得冗余,代码移植性差,在stm32f10x标准库函数中,有大量不同种类的常量,这时候就需要用到enum枚举类型对常量进行归类。先看一个例子>>>
/*有多种定义形式*/
enum time
{hour, minute = 25, second}now;
enum
{hour, minute = 25, second}now;
enum time
{hour, minute = 25, second};
enum基本用法如上所示,可以有多种形式进行枚举类型定义。time作为枚举类型名字通常并不使用,用的是大括号中的枚举元素,且编译器会将这些元素当作整形常量处理,在数值方面,如果第一个元素没有赋值,会默认为0,后面没有被赋值的元素的数值为前一元素值加1,在取用枚举元素的值时就可以直接使用枚举元素。在赋值方面,枚举元素可以直接赋给int类型变量,但int类型常量不能直接赋给枚举类型变量,需要强制转换才能完成。
printf("The time is %02d : %02d : %02d", hour, minute, second);//直接使用枚举元素
>>>The time is 00 : 25 : 25
/***************************************************/
enum time
{
hour,
minute = 25,
second
};//定义枚举
enum time hour = (enum time)12;//定义一个枚举变量hour并给枚举类型变量赋值
int main(){
printf("hour = %d", hour);//输出结果
return 0;
}
>>>hour = 12;
在stm32中的应用
在stm32中,更多是typedef加枚举的应用,可见下图示例
typedef 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
}GPIOMode_TypeDef;
GPIOMode_TypeDef GPIO_Mode;
GPIO_Mode = GPIO_Mode_IPU;
这里用了typedef数据类型定义,使得GPIOMode_TypeDef变成枚举数据类型,并且定义了一个枚举型变量GPIO_Mode,将枚举元素GPIO_Mode_IPU赋值给它,之后就可以直接对GPIO_Mode进行操作了,也是体现了库函数很好的可读性、可移植性。
·C结构体类型
基本定义
C 数组允许定义可存储相同类型数据项的变量,结构是 C 编程中另一种用户自定义的可用的数据类型,它允许存储不同类型的数据项。结构体的定义方法如下
struct tag {
member-list
member-list
member-list
...
} variable-list ;
tag:结构体类型名字(可选择)
member-list:(标准的变量定义)
variable-list:共用体变量(可选择)
也可以用typedef创建新类型,这里用simple1来声明新的结构体变量。
typedef struct
{
int a;
char b;
double c;
}simple1;
simple1 simple2;
初始化
struct结构体标识符 变量名 = {初始化值1,初始化值2…,初始化值n};
例如现在用一本书作为例子,一本书的信息包括书名、页数、作者、主题。于是有如下定义和初始化
struct books
{
int pages;
char author[10];
char subject[50];
};
struct books To_live = {194, "YuHua", "to live"};
作为函数参数
如果想要将一个结构传入函数,可以有以下两种方式实现,一个是传入普通的结构参量,然后再定义一个新的结构体复制传入的结构(与数组不同,两个结构变量可以相互赋值)。这个用法不常用,更多是用结构体指针来传入结构体变量。K&R曾经说过"if a large structure is to be passed to a function, it is generally more efficient to pass a pointer than to copy the whole structure"。由此可见,结构作为指针传入函数是最有效的。详细用法见下面实例
#include <stdio.h>
struct books
{
int pages;
char author[10];
char subject[50];
};
/* 函数声明 */
void printBook( struct books *book );
int main( )
{
/* 声明 Book1,类型为 books */
struct books To_live = {194, "YuHua", "to live"};
/* 通过传 《活着》 的地址来输出 Book1 信息 */
printBook( &To_live );
return 0;
}
void printBook( struct books *book )
{
printf( "To_live pages : %d\n", book->pages);//取用结构体成员时,用标识符”->“
printf( "To_live author : %s\n", book->author);
printf( "To_live subject : %s\n", book->subject);
}
输出结果
在stm32中的应用
在stm32f10x固件库中,更多的是结构体与枚举的综合运用,下面是关于GPIO模式配置的部分代码
typedef 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
}GPIOMode_TypeDef;
typedef struct
{
uint16_t GPIO_Pin;
GPIOMode_TypeDef GPIO_Mode;
}GPIO_InitTypeDef;
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
/*后面是对GPIO_Mode的一系列操作,使单片机执行指令*/
不难看出,这里枚举和结构都是用typedef 来定义一个数据类型定义,这也是为了用户取用代码方便,用户在主函数中定义了一个结构体变量GPIO_InitStructure,并且对结构体成员(也是一个枚举类型)GPIO_Mode进行赋值操作。
·C共用体类型
基本定义
C共用体是一种特殊的数据类型,与结构体类似,但不同的是允许用户在相同的内存位置存储不同的数据类型,我们可以定义一个带有多成员的共用体,但是任何时候只能有一个成员带有值。共用体提供了一种相同的内存位置的有效方式(即一个变量可以有多个数据类型)即可以赋值不同数据类型的数据,但一次只能赋值一个。首先是共用体的定义
union [union tag]
{
member definition;
member definition;
...
member definition;
} [one or more union variables];
union tag:共用体类型名字(可选择)
member definition:共用体元素(标准的变量定义)
one or more union variables:共用体变量(可选择)
访问公用体成员时需要访问运算符
union Data
{
int i;
char s[20];
double m;
}data;
strcpy(data.str, "Hello_World!");
printf("data.str = %s", data.str);
>>>Hello_World!
内存空间
共用体占用的内存应足够存储共用体中最大的成员。例如,在上面的实例中,Data 将占用 20 个字节的内存空间,因为在各个成员中,字符串所占用的空间是最大的。下面的实例将显示上面的共用体占用的总内存大小:
union Data
{
int i;
char s[20];
double m;
}data;
printf("memory size occupied by data is %d", sizeof(data));
>>>memory size occupied by data is 20
共用
共用体里的所有成员公用一个内存位置,只有在同一时间内只用到一个值,才不会出错
union Data
{
int i;
char s[20];
double m;
}data;
data.i = 10;
printf( "data.i : %d\n", data.i);
data.m = 984.5;
printf( "data.m : %f\n", data.m);
strcpy( data.s, "Hello_World!");
printf( "data.s : %s\n", data.s);
printf("\n");
printf( "data.i : %d\n", data.i);
printf( "data.m : %f\n", data.m);
printf( "data.s : %s\n", data.s);
代码运行结果如下
可以发现前二次输出的结果有损坏,原因就在于data.s将共用体唯一 一个内存空间给占据了,所以只有data.s输出正确。
详细的共用体用途介绍
END