枚举是 C 语言中的一种基本数据类型,它可以让数据更简洁,更易读。
枚举的初衷是为了替代宏的用法 。
枚举语法定义格式为:
enum 枚举名 {枚举元素1,枚举元素2,……};
enum WEEK {Mon,Tue,Wed,Tur,Fri,Sat,Sun};
实例13
源文件
03-chigh/13-enum.c
#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;
}
0 1 2 3 4 5 6
Thu=3
03-chigh/14-enum.c
#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
Mon=1
Tue=2
Wed=3
Thu=4
Fri=5
Sat=6
Sun=7
枚举类型举例
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
} ;
typedef这个关键字用来定义一个新的数据类型
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 类型
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 ;
typedef enum
{
GPIO_Speed_10MHz = 1, // 可以在程序中把这个枚举常量当成宏(标识常量)去使用
GPIO_Speed_2MHz, // 2
GPIO_Speed_50MHz // 3
}GPIOSpeed_TypeDef;
// typedef { ... } 这个结构体类型的别名是 GPIOSpeed_TypeDef
// func 是一个函数名
// 也是一个函数的入口地址
// 也是函数的首地址
int func(int a, int b); // 这是函数声明
// 加上typedef 后, func_t就不再是函数名了, 是一个函数类型
// 参数是(int , int )
// 返回值 int
// 可是使用func_t 来定义一个函数指针
typedef int func_t(int a, int b) ;
03-chigh/15-typedef.c
#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;
}
ret=30
ret=-10
ret=200
ret=0
有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有 0 和 1 两种状态,用 1 位二进位即可。为了节省存储空间,并使处理简便,C 语言又提供了一种数据结构,称为"位域"或"位段"。
所谓"位域"是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。
典型的实例:
位域定义与结构定义相仿,其形式为:
struct 位域结构名
{
位域列表
};
其中位域列表的形式为:
type [member_name] : width ; // 数据类型 变量名称:暂用二进位的宽度 ;
03-chigh/16-weiyu.c
#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;
}
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
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;