温馨提示:本文翻译自stackoverflow.com,查看原文请点击:c - Understanding #define preprocessor directive macro syntax
c pointers c-preprocessor lpc

c - 了解#define预处理程序指令宏语法

发布于 2020-03-27 11:18:08

以下代码取自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该指针指向SYSCON_Type存储在地址中的类型变量0x40000000u这真的发生了吗?是否有任何资源说明此处使用的语法(即在宏内定义指针)?

  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;  
}

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

任何答案将不胜感激!

查看更多

查看更多

提问者
Vincent
被浏览
158
Lundin 2019-07-03 22:35
#define SYSCON_BASE         (0x40000000u)

这只是在物理地址上列出0x40000000

#define SYSCON ((SYSCON_Type *)SYSCON_BASE)

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

简而言之,它说“在地址0x40000000处有一个硬件外设SYSCON”(无论是什么计时器?)。常见的情况是,MCU内有多个相同类型的硬件外设(许多SPI,ADC等),每个硬件外设具有相同的寄存器布局,但位于不同的地址。我们可以为每个此类外设使用相同的结构类型,也可以使用相同的驱动程序代码。

该结构本身将具有一个内存映射,该映射对应于寄存器布局的100%。这里重要的是要确保填充/对齐不会搞砸,但希望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获得了可以根据偏移量移动的特殊指令,因此实际机器代码中的指令可能更少。后续的寄存器访问可以使“ X”保持不变,并反复使用该基址来获得有效的代码。)

__IO预选赛中仅仅是代码膨胀隐藏volatile

尝试“直接写入结构”时出现错误的原因仅仅是因为您无法在所有函数之外执行代码,而与该结构无关。