• C语言(三)- 结构体、结构体指针、位运算


    一、结构体

    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={620,2015};       //char字符型变量使用" "
     7 
     8 
     9 或者
    10 
    11 struct Date birthday1={620,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

  • 相关阅读:
    org.hibernate.annotationexception no identifier specified for entity
    PL/SQL Developer 中文乱码解决
    cron表达式
    mysql远程连接的设置
    linux查看端口对应的程序及pid
    安卓开发分享功能,分享到facebook网页上不显示图片的问题
    win7下解压安装mysql的方法
    总结一下论文写作过程中的一些东西
    java中可以让程序暂停几秒执行的代码
    Neo4j图数据库使用
  • 原文地址:https://www.cnblogs.com/wuguangzong/p/8952367.html
Copyright © 2020-2023  润新知