了解#define 预处理器指令宏语法

Understanding #define preprocessor directive macro syntax

以下代码摘自LPC54618.h头文件:

typedef struct {
     //...structure elements
     __IO uint32_t SDIOCLKSEL;
     //...more elements

} SYSCON_Type;

#define SYSCON_BASE         (0x40000000u)
#define SYSCON              ((SYSCON_Type *)SYSCON_BASE)
  1. 据我所知,这行背后的意思

    #define SYSCON ((SYSCON_Type *)SYSCON_BASE)

我假设它创建了一个名为 SYSCON 的指针,该指针指向存储在地址 0x40000000uSYSCON_Type 类型的变量。这真的发生了吗?是否有任何资源可以解释此处使用的语法(即在宏中定义指针)?

  1. 当我试图直接改变 SDIOCLKSEL 的值时,即:

    SYSCON->SDIOCLKSEL = some value;

    我得到一个错误:

    error: expected ')' error: expected parameter declarator error: expected ')' error: expected function body after function declarator

但是如果我在一个函数中使用它,例如:

void foo(void)
{
   SYSCON->SDIOCLKSEL = some value;  
}

没有错误。这是为什么?为什么我不能直接写入结构?

任何答案将不胜感激!

非常简单。

that it creates a pointer named SYSCON that points to a variable of type SYSCON_Type which is stored at the address 0x40000000u. Is this really what happens?

是也不是。当你使用宏 SYSCON

void foo(uint32_t value)
{
   SYSCON->SDIOCLKSEL = value;
}

预处理器转换为:

void foo(uint32_t value)
{
  ((SYSCON_Type *)0x40000000u)->SDIOCLKSEL = value;
}

将 32 位无符号 value 写入地址为 0x40000000u + 结构成员偏移量的内存位置。

通常用于访问映射到内存地址space的硬件寄存器。

你需要在函数内部完成(C语言中的所有代码)

#define SYSCON_BASE         (0x40000000u)

这只是列出物理地址 0x40000000

#define SYSCON ((SYSCON_Type *)SYSCON_BASE)

这通过强制转换将整数常量 0x40000000u 转换为指向结构的指针。它实际上并没有分配任何东西——实际的寄存器已经分配为 memory-mapped 硬件。

简单地说,它表示 "at address 0x40000000 there's a hardware peripheral SYSCON"(不管那是什么,某个计时器?)。这是一种常见的情况,您在 MCU 中有多个相同类型的硬件外设(许多 SPI、ADC 等),每个都具有相同的寄存器布局,但位于不同的地址。我们可以为每个这样的外围设备使用相同的结构类型,也可以使用相同的驱动程序代码。

结构本身将有一个与寄存器布局 100% 对应的内存映射。这里重要的是要确保 padding/alignment 不会搞砸,但希望 MCU 制造商已经想到了这一点(尽管不要认为这是理所当然的)。

假设 SDIOCLKSEL 的寄存器偏移量为 0x10,那么当您键入 SYSCON->SDIOCLKSEL = some value; 时,您会得到这样的机器码(伪汇编代码):

LOAD 0x40000000 into index register X  
LOAD 0x10 into register A
ADD A to X
MOVE some value into the address of X

(ARM 有特殊指令可以根据偏移量移动 etc,因此实际机器代码中的指令可能更少。后续的寄存器访问可以保持 "X" 不变并重复使用该基地址,因为有效代码。)

__IO 限定符只是代码膨胀隐藏 volatile

你尝试"write directly into the structure"时出错的原因很简单,你不能执行所有函数之外的代码,它与这个结构无关。