目录
1.struct声明结构体
2.定义结构体变量
3. typedef
(1)采用struct和 typedef struct 声明结构体是有区别的
(2)对比,使用typedef struct 声明结构体
4.GPIO_TypeDef是结构体名称,而不是结构体变量
typedef和用struct都可以用来定义结构体,采用struct和采用typedef struct 声明结构体是有区别的。
1.struct声明结构体
结构体是一种自定义的数据类型,可以将不同类型的数据组合在一起,构成一个组合型数据结构。
struct b_type
{
uiny32_t _reserved0:27; /*! bit:0..26 */
uiny32_t Q:1; /*! bit:27 */
uiny32_t V:1; /*! <bit:28 */
uiny32_t C:1; /*! <bit:29 */
uiny32_t Z:1; /*! <bit:30 */
uiny32_t N:1; /*! <bit:31 */
};
其中,struct是声明结构体的关键字,b_type是结构体的名称。{}里的内容是结构体的成员。在b_type结构体里有6个成员,它们的数据类型都是uint32_t。结构体中各成员的数据类型可以不同。
2.定义结构体变量
上面的声明的结构体并没有定义结构体变量,只是建立了一个名为b_type的结构体类型。如果仅仅如此,编译的时候,是不会给这个结构体分配存储单元的。
上面声明的b_type结构体可以通过下面的语句定义变量:
struct b_type b; // b为结构体变量名
也可以在声明结构体时定义结构体变量,其效果是相同的:
struct b_type
{
uiny32_t _reserved0:27; /*! bit:0..26 */
uiny32_t Q:1; /*! bit:27 */
uiny32_t V:1; /*! <bit:28 */
uiny32_t C:1; /*! <bit:29 */
uiny32_t Z:1; /*! <bit:30 */
uiny32_t N:1; /*! <bit:31 */
} b;
此外,在声明结构体时还可以不指定结构体类型名,直接定义结构体变量:
// 直接定义结构体变量GPIO_InitTypeDef
struct
{
uint32_t Pin;
uint32_t Mode;
uint32_t Pull;
uint32_t Speed;
} GPIO_InitTypeDef;
结构体类型和结构体变量是不同的概念,编译时只会对变量分配内存空间,并且只可对变量进行赋值等操作。因此,声明结构体后,如果要使用它,就一定要定义该结构体的变量。
3. typedef
typedef是C语言中的关键字,它的作用是为其后面的数据类型定义一个“别名”,新的名字。此处所说的其后的数据类型可以是int、char等常用的数据类型,也可以是结构体struct这样的自定义数据类型。使用typedef的目的是简化类型声明,给变量类型定义新名字。
(1)采用struct和 typedef struct 声明结构体是有区别的
如下,以struct声明了b_type结构体并定义变量b:
struct b_type // b_type不是变量名,而是结构体名,并且可以省略
{
// 类型成员名
} b; // b是结构体变量
如果,再定义另一个结构体变量aaa,可以:
struct b_type aaa;
(2)对比,使用typedef struct 声明结构体
typedef struct a_type // a_type是结构体名称,可以省略
{
// 类型 成员名
} a_type_new; // a_type_new是结构体新的成员名称,不是变量名
此处,{}后面的a_type_new不再是结构体变量,而是结构体a_type的别名。此时若定义该结构体的变量aaa,可以:
struct a_type aaa;
或
struct a_type_new aaa;
4.GPIO_TypeDef是结构体名称,而不是结构体变量
/**
* @brief General Purpose I/O
*/
typedef struct
{
__IO uint32_t MODER; /*!< GPIO port mode register, Address offset: 0x00 */
__IO uint32_t OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */
__IO uint32_t OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */
__IO uint32_t PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */
__IO uint32_t IDR; /*!< GPIO port input data register, Address offset: 0x10 */
__IO uint32_t ODR; /*!< GPIO port output data register, Address offset: 0x14 */
__IO uint32_t BSRR; /*!< GPIO port bit set/reset register, Address offset: 0x18 */
__IO uint32_t LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */
__IO uint32_t AFR[2]; /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */
__IO uint32_t BRR; /*!< GPIO Bit Reset register, Address offset: 0x28 */
} GPIO_TypeDef;
其中,数据类型前面的__IO在固件库中通过define宏定义为volatile:
# define __IO volatile;
C语言中,变量前加volatile是提醒编译器不用对变量进行优化,调用该变量时,每次都到变量所在寄存器中去读它的内容。
进一步地,在单片机中,比如在stm32g474xx.h文件中,很多形如GPIO_TypeDef的结构体,都是结构体名称,而不是结构体的变量。