如何声明一个指向volatile结构体的指针

4
假设我有以下定义:
/* Generic structure of entire SFR area for each UART module */
typedef struct tagUART {
        unsigned int uxmode;
        unsigned int uxsta;
        unsigned int uxtxreg;
        unsigned int uxrxreg;
        unsigned int uxbrg;
} UART, *PUART;



/* SFR blocks for each UART module */
extern volatile UART UART1 __attribute__((__sfr__));
extern volatile UART UART2 __attribute__((__sfr__));

如果我通过UART1访问寄存器,一切都很好,但是如果我使用指向结构体的指针,我应该如何声明它以指定指向的整个区域是易失性的?

volatile UART * hw = &UART1;

可以的吗?(Is that ok ?)
2个回答

4
如果您声明
extern volatile UART UART1;

那么从该变量派生的任何指针都将是volatile UART *类型,事实上,如果您尝试将其分配给其他类型的变量,则编译器应发出警告。

如果您希望UART始终为volatile,则可以将其定义为typedef

typedef volatile struct {...} tagUART UART;

或者像unwind所说的那样,将特定字段声明为volatile。
typedef struct tagUART {
        volatile unsigned int uxmode;
        unsigned int uxsta;
        volatile unsigned int uxtxreg;
        unsigned int uxrxreg;
        unsigned int uxbrg;
} UART, *PUART;
volatile 的内联使用,即
while (*(volatile int *)&a) ;

不鼓励使用volatile关键字,只应用于通常不易变的变量,在这种情况下必须使用。

另一种方法是使用union,其中访问一个版本是易变的而另一个版本则不是:

union {
    volatile UART volatile_version;
    UART normal;
};

1
由于不存在不希望UART寄存器成为易失性的情况,因此在整个结构体上使用typedef volatile是正确的方式。 - Lundin
你确定你的第一点,即 UART * hw = &UART1 是足够的,并且 volatile 将被传递到指针中吗? - shodanex
@shodanex 对 volatile 变量取地址会返回 volatile 指针,但是如果你打算将该地址保存在另一个变量中,则该变量也需要带有 volatile&UART1 的类型为 volatile UART *,但是 UART * hw = &UART1 将调用一个指向非 volatile 指针的类型转换 - 在这里,你需要写成 volatile UART * hw = &UART1 - Sergey L.

1
我认为那是错误的方式;如果有人(即三个月后的您)使用指向USART的指针,但忘记了volatile部分怎么办?
正确的方法是将每个字段声明为volatile。这有点混乱,但更好,因为它在代码中捕获了更多你尝试建模的内容。
通常可以看到像__IO这样的宏用于模拟硬件寄存器的结构体字段,并且它通常包括在其扩展中。volatile

我同意,但由于这是“供应商提供”的包含文件,我希望避免修改它。当然,我可以重新声明整个内容... - shodanex

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接