GPIO 外设何时分配其成员地址?

When does GPIO peripheral get its members addresses assigned?

stm32f446xx.h 我们有一个定义 GPIO_TypeDef

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 */
} GPIO_TypeDef;

这个用来初始化一些GPIO外设。关注GPIOA:

#define PERIPH_BASE           ((uint32_t)0x40000000)
#define AHB1PERIPH_BASE       (PERIPH_BASE + 0x00020000)
#define GPIOA_BASE            (AHB1PERIPH_BASE + 0x0000)
#define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE)

所以我的问题是:

  1. #define 指令是否声明和初始化结构并将其放在指向 `GPIOA_BASE 的地址?或者 define 语句只是声明结构而不初始化其成员?

  2. 成员如何在没有明确定义的情况下正确放置地址?我们如何知道 GPIOA->MODER 指向与 GPIOA_BASE 相同的地址?同样,我们如何知道 GPIOA->ODR 导致地址 GPIOA_BASE + 偏移量 0x014?仅仅是因为当我们声明结构并告诉它它位于 GPIOA_BASE#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE) 命令时,它的所有成员变量都按照它们在结构 [=21] 中出现的顺序在内存中声明和初始化=]?这是有道理的,因为每个占用 4 个字节,但我不确定是否是这种情况。

  3. 如果成员变量没有按照它们在结构中列出的顺序声明,那么它们如何分配内存地址?

名称"C"用于描述两件事:

  1. 一个以相当一致的方式将源代码构造映射到目标机构造的语言家族。通常没有 "standard" 记录应如何执行此类映射,并且不常见目标平台的实现与更常见目标平台的实现行为不同,但类似平台的编译器通常行为相似。

  2. 一种仅包含 C11 标准规定的功能的语言,通常会忽略并非在所有平台上一致实现的功能,即使类似平台的 C 编译器会以类似方式处理它们。

您上面引用的代码是为处理第一族语言的编译器设计的,它适应了 ARM 处理器的需要。在该语言中,结构的每个项目都将放置在满足其对齐要求的最低偏移处。 C11 标准及其任何前身均不要求编译器保证以这种方式布置结构,对于那些有时以其他方式指示该事实的人来说,它们中的任何一个甚至都不提供任何方便的方式。从 C11 标准的角度来看,结构元素可以任意放置,受制于相对较少的约束。我认为 C89 的作者可能认为编译器编写者会在有或没有授权的情况下按顺序安排事情,除非在极少数平台上可能有令人信服的理由不这样做,因此没有理由要求他们按他们的方式行事无论如何都会去。然而,有些人似乎认为缺少授权意味着公开邀请任意安排事物,任何依赖于特定布局的代码都应被视为 "defective".