一、结构体
1、一般形式
不同类型数据组成的组合型数据结构,即结构体。
结构体类型的一般形式:
1 struct 结构体名{ 2 类型名 成员名1; 3 类型名 成员名2; 4 类型名 成员名3;
5 ...... 6 };
举个例子:
1 #include<stdio.h> 2 int main(void) 3 { 4 struct Date 5 { 6 int month; 7 int day; 8 int year; 9 }; 10 struct Student 11 { 12 int num; 13 char name[20]; 14 char sex; 15 int age; 16 struct Date birthday; //birthday是一个struct Date结构体类型变量,即birthday使用了strcut Date结构体的数据结构形式 17 char addr[30]; 18 }; 19 }
2、定义结构体类型变量
1 struct Date //声明结构体类型,再定义是此类型的变量 2 { 3 int month; 4 int day; 5 int year; 6 }; 7 struct Date birthday1,birthday2; 8 9 或者 10 11 struct Date //在声明结构体类型的同时定义是此类型的变量 12 { 13 int month; 14 int day; 15 int year; 16 } birthday1,birthday2;
3、结构体变量初始化和引用
使用上述 struct Date 结构体来进行说明。
3.1初始化
1 struct Date //声明结构体同时初始化 2 { 3 int month; 4 int day; 5 int year; 6 } birthday1={6,20,2015}; //char字符型变量使用" " 7 8 9 或者 10 11 struct Date birthday1={6,20,2015}; //先如上声明结构体,再初始化 12 13 14 除此之外还可以对某一单一成员变量初始化: 15 struct Date birthday1={.month=6};
3.2成员变量操作
结构体变量名.成员名
如:birthday1.month
结构体变量名.成员名.子成员名
如:student1.birthday1.month
注:
(1) . 是成员运算符,所有运算符中优先级最高,使用后相当于一个整体,即一个变量。
(2)成员变量及之间可以进行算术运算。
(3)同类的结构体变量可以相互赋值,如:birthday1=birthday2
(4)可以引用结构体成员变量的地址,也可以引用结构体变量的地址。
1 scanf("%d",&birthday1.month); //输入&birthday1.month的值 2 3 printf("%d",&birthday1); //输出结构体变量&birthday1的首地址,即birthday1.month
(5)在scanf函数中,如果结构体成员变量是数组,其本身就代表地址,前面不需要添加取地址符&。
二、结构体数组
结构体数组一般形式:
1 struct 机构体名 2 { 3 2 类型名 成员名1; 4 3 类型名 成员名2; 5 4 类型名 成员名3; 6 5 ...... 7 }数组名[ 数组长度 ]; 8 9 或者 10 11 结构体类型 数组名[ 数组长度 ]; //先声明好结构体类型
举例子:
1 #include<string.h> //字符数组头文件 2 #include<stdio.h> 3 struct Person 4 { 5 char name[20]; //参选人名 6 int count; //合计票数 7 }leader[3]={"ergouzi",0,"xiaobai",0,"goudaner",0}; 8 //定义结构体数组并初始化,三个人起始都是0票 9 10 11 或者 12 13 strcut Person leader[3]={"ergouzi",0,"xiaobai",0,"goudaner",0};
注:结构体数组相对于结构体,简化了结构体变量定义,通过数组一次性定义很多结构体变量。
三、结构体指针
一个变量的地址称为该变量的指针,指针即内存地址。
①指针就是地址,地址就是指针;②地址是内存单元的编号;③指针变量就是存放内存地址的变量。
&:取变量地址运算符,一般后接整型浮点型变量。*:取指针变量所指向的变量的内容的运算符,后接指针变量(即地址)。
1 int x,y; 2 int *p; //表示p是指向整型量的指针变量,此时没有赋指针变量值,更不存在指向变量的内容。 3 x=10; 4 p=&x; //将整型变量x的地址赋给了p,此时存在了指向变量的内容 5 y=*p; //将p所指向的变量的内容赋给了y, 即y=10
结构指针是指向一种结构体类型的指针变量,它是结构体在内存中的首地址。
地址:在内存中每8bit物理长度(即1字节)给的一个编号。在stm32f103zet6中存储器有4GB的地址空间:
4GB的地址空间按照功能划分成8块,以Block 0为例:地址总数为0x2000 0000,换算成十进制为2*(16^7)= 536870912B = 512*1024*1024B =512*1024KB = 512MB
stm32f103zet6为32处理器,寄存器也是32位。8位一个地址,单个寄存器的地址偏移量为4个地址。
地址在C语言编程时,0x0000 0004在编译器来看只是一个十六进制数字,需要地址强制转换(unsigned int *)0x0000 0004。
以stm32f103zet6中GPIOB寄存器的封装为例讲解结构体指针:
1 /* 2 GPIOx(A-G)是片上外设,为了系统化和结构化的封装寄存器,引入了结构体指针 3 */ 4 /*外设基地址*/ 5 #define PERIPH_BASE ((unsign int)0x40000000) 6 /*总线基地址*/ 7 #define APB1PERIPH_BASE PERIPH_BASE 8 #define APB2PERIPH_BASE ((unsign int)0x00010000) 9 #define AHBPERIPH_BASE ((unsign int)0x00020000) 10 /*GPIO外设基地址*/ 11 #define GPIOA_BASE (APB2PERIPH_BASE + 0x0800) 12 #define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00) 13 #define GPIOC_BASE (APB2PERIPH_BASE + 0x1000) 14 #define GPIOD_BASE (APB2PERIPH_BASE + 0x1400) 15 #define GPIOE_BASE (APB2PERIPH_BASE + 0x1800) 16 #define GPIOF_BASE (APB2PERIPH_BASE + 0x1C00) 17 #define GPIOG_BASE (APB2PERIPH_BASE + 0x2000) 18 /*寄存器基地址,GPIOB为例*/ 19 #define GPIOB_CRL (GPIOB_BASE + 0x00) 20 #define GPIOB_CRH (GPIOB_BASE + 0x04) 21 #define GPIOB_IDR (GPIOB_BASE + 0x08) 22 #define GPIOB_ODR (GPIOB_BASE + 0x0C) 23 #define GPIOB_BSRR (GPIOB_BASE + 0x10) 24 #define GPIOB_BRR (GPIOB_BASE + 0x14) 25 #define GPIOB_LCKR (GPIOB_BASE + 0x18) 26 /*此时已知寄存器具体地址,可以通过指针&*赋值操作控制寄存器*/ 27 /*GPIOx都有一组功能相似的寄存器,只是地址不同却要为每个寄存器定义地址。为了方便访问寄存器,引入结构体封装寄存器*/ 28 29 30 /*使用结构体封装GPIO寄存器组*/ 31 typedef unsigned int uint32_t; //无符号32位变量 32 typedef unsigned short int uint16_t; //无符号16位变量 33 /*GPIO寄存器列表*/ 34 typedef struct{ 35 uint32_t CRL; //端口配置低寄存器 地址偏移:0x00 36 uint32_t CRH; //端口配置高寄存器 地址偏移:0x04 37 uint32_t IDR; //数据输入寄存器 地址偏移:0x08 38 uint32_t ODR; //数据输出寄存器 地址偏移:0x0C 39 uint32_t BSRR; //位设置/清除寄存器 地址偏移:0x10 40 uint32_t BRR; //端口位清除寄存器 地址偏移:0x14 41 uint16_t LCKR; //端口配置锁定寄存器 地址偏移:0x18 42 }GPIO_TypeDef; 43 /*以上代码用typedef关键字声明了名为GPIO_TypeDef的结构体,结构体有七个成员变量。C语法,结构体内变量的存储空间是连续的,32位变量占4字节,16变量占2字节,连续排列。
因此,给结构体设置好首地址,那么结构体成员的地址就确定下来,然后以结构体的形式访问寄存器。*/ 44 45 /*结构体指针访问寄存器*/ 46 /*一般过程*/ 47 GPIO_TypeDef *GPIOx;//定义一个GPIO_TypeDef型结构体指针GPIOx 48 GPIOx = GPIOB_BASE;//GPIOx指针变量,把指针地址设为宏GPIOB_BASE地址 49 GPIOx->CRL = 0xFFFF; 50 uint32_t temp; 51 temp = GPIOx->CRL;//读取GPIOx_CRL寄存器的值到变量temp中 52 53 /*定义好GPIO端口首地址指针*/ 54 #define GPIOA ((GPIO_TypeDef *) GPIOA_BASE) 55 #define GPIOB ((GPIO_TypeDef *) GPIOB_BASE) 56 #define GPIOC ((GPIO_TypeDef *) GPIOC_BASE) 57 #define GPIOD ((GPIO_TypeDef *) GPIOD_BASE) 58 #define GPIOE ((GPIO_TypeDef *) GPIOE_BASE) 59 #define GPIOF ((GPIO_TypeDef *) GPIOF_BASE) 60 #define GPIOG ((GPIO_TypeDef *) GPIOG_BASE) 61 #define GPIOH ((GPIO_TypeDef *) GPIOH_BASE) 62 /*使用定义好的宏直接访问GPIOB端口的寄存器*/ 63 GPIOB->BSRR = 0xFFFF; 64 GPIOB->CRL = 0xFFFF; 65 GPIOB->ODR = 0xFFFF; 66 uint32_t temp; 67 temp = GPIOB->IDR;//读取GPIOB_IDR寄存器的值到变量temp中 68 69 70 /*(以下是访问结构体成员的说明)声明了两个变量,一个是指向结构GPIO_TypeDef的结构指针PGPIOB,GPIOB是一个GPIO_TypeDef结构变量*/ 71 struct GPIO_TypeDef *PGPIOB,GPIOB; 72 PGPIOB = &GPIOB; 73 /*结构体变量访问成员变量(以下三者是等价的)*/ 74 GPIOB.ODR = 0xFFFF; 75 /*结构体指针访问成员变量*/ 76 (*PGPIOB).ODR = 0xFFFF;//*优先级低于.,所以加() 77 PGPIOB->ODR = 0xFFFF;
三、位运算(二进制运算)
基本运算符:
&按位与:均为1结果为1,否则为0。
|按位或:有一个为1,结果为1。
^按位异或:二进位相异,结果为1。
~取反:0变1,1变0。
<<左移:<<左边的运算数的各二进制左移若干位(<<右边的数为指定的位移数)
>>右移:>>左边的运算数的各二进制右移若干位(>>右边的数为指定的位移数)
1 /*某一位清零: a &= ~(1<<x)*,二进制a右侧bitx清零/ 2 3 unsigned char a= 0x9f; //a=1001 1111 b 4 a &= ~(1<<2); //对bit2清零 5 /* 6 0000 0100 b //b表示二进制数 7 1111 1011 b 8 a = (1001 1111 b)&(1111 1011 b) 9 a = 1001 1011 b 10 */ 11 12 13 /*连续位清零:a &= ~(y<<x*k)*,y运算数,x一组数的位数,k组数*/ 14 a &= ~(3<<2*1); //运算数为3,每组位数为2位,清零第1组 15 //bit0、bit1为第0组,bit2、bit3为第1组 16 /* 17 0000 1100 b 18 1111 0011 b 19 a = (1001 1111 b)&(1111 0011 b) 20 a = 1001 0011 b 21 */ 22 23 24 /*连续位赋值*/ 25 unsigned char b= 1000 0011b; 26 b |= (1<<2*2); 27 /* 28 0001 0000 b 29 b = (1000 0011 b)|(0001 0000 b) 30 b = 1001 0011 b 31 */ 32 33 34 /*某一位取反*/ 35 //此时b = 1001 0011 b 36 b ^=(1<<6) //bit6取反 37 /* 38 0100 0000 b 39 b = (1001 0011 b)^(0100 0000 b) 40 b = 1101 0011 b 41 */
7