簡體   English   中英

只讀內存映射寄存器在C中用`volatile const`定義,但在C ++中只用`volatile`定義

[英]Read-only memory-mapped registers defined with `volatile const` in C but only `volatile` in C++

在使用Atmel SAM3X8E處理嵌入式系統項目時,我注意到某些CMSIS頭文件中的以下代碼。

#ifndef __cplusplus
typedef volatile const uint32_t RoReg; /**< Read only 32-bit register (volatile const unsigned int) */
#else
typedef volatile       uint32_t RoReg; /**< Read only 32-bit register (volatile const unsigned int) */
#endif

為什么C ++的typedef不包含const 我在某處看到C ++沒有在運行時內存中存儲整數const變量,如果為true則意味着需要刪除const因為微控制器寄存器是如何進行內存映射的,但我似乎無法找到其他任何說法C ++就是這樣做的(盡管我的搜索非常簡短)。 我沒有太多的C ++經驗,我也認為可能是C ++不允許使用const結構成員,因為那些typedef主要用於struct typedef用於寄存器集合,但似乎也不是這樣。

如果用const聲明,C ++標准將強制您初始化變量的內容。 在微控制器寄存器的情況下,您不希望這樣做。

因為沒有實例化RoReg對象,所以沒有充分的理由在typedef中省略const限定符。

RoReg每次使用都在一個定義指向該類型的指針的宏中......

#define REG_WDT_SR (*(RoReg*)0x400E1A58U) /**< \brief (WDT) Status Register */

...或使用類似宏訪問的struct聲明。

typedef struct {
  WoReg WDT_CR; /**< \brief (Wdt Offset: 0x00) Control Register */
  RwReg WDT_MR; /**< \brief (Wdt Offset: 0x04) Mode Register */
  RoReg WDT_SR; /**< \brief (Wdt Offset: 0x08) Status Register */
} Wdt;

#define WDT        ((Wdt    *)0x400E1A50U) /**< \brief (WDT) Base Address */

即使使用const限定符,代碼在C和C ++中的行為也應該相同。

也許作者誤解了標准。 為了保證C ++結構具有與C中相同的布局,它要求類“對所有非靜態數據成員具有相同的訪問控制(第11條)”。 作者可能誤認為訪問控制說明符的constvolatile 如果是,那么您希望所有結構成員具有相同的cv限定符,以確保C和C ++(和硬件)布局之間的兼容性。 但它是publicprotectedprivate ,用於定義訪問控制。

正如@fanl所提到的, const確實改變了C ++中全局變量的默認鏈接,並且確實阻止了在沒有初始化的情況下定義變量。

但是有更好的方法來獲得外部鏈接而不是刪除const 在鏈接的頭文件中保留數組的使用也非常脆弱。 我會說這段代碼留下了很大的改進空間 - 不要模仿它。

而且這些變量沒有定義(這會導致編譯器和鏈接器選擇一個地址),它們總是通過指針訪問,地址根據內存映射固定。

對於純粹供C ++使用的標頭,我就是這樣做的(內存映射匹配TI Stellaris芯片)。

看起來很復雜,但優化編譯器將其縮減為每次訪問一條指令。 並且地址偏移被編碼,而不依賴於結構內的字段的順序和填充,因此它更不易碎並且更容易根據數據表進行驗證。

template<uintptr_t extent>
struct memory_mapped_peripheral
{
    char data[extent];
    volatile       uint32_t* offset( uintptr_t off )       { return reinterpret_cast<volatile       uint32_t*>(data+off); }
    volatile const uint32_t* offset( uintptr_t off ) const { return reinterpret_cast<volatile const uint32_t*>(data+off); }
};

struct LM3S_SYSTICK : private memory_mapped_peripheral<0x1000>
{
    volatile       uint32_t& CTRL   (void)             { return offset(0x010)[0]; }
    volatile       uint32_t& RELOAD (void)             { return offset(0x014)[0]; }
    volatile       uint32_t& CURRENT(void)             { return offset(0x018)[0]; }
}* const SYSTICK = reinterpret_cast<LM3S_SYSTICK*>(0xE000E000);

struct LM3S_NVIC : private memory_mapped_peripheral<0x1000>
{
    volatile       uint32_t& EN    (uintptr_t i)       { return offset(0x100)[i]; }
    volatile       uint32_t& DIS   (uintptr_t i)       { return offset(0x180)[i]; }
    volatile       uint32_t& PEND  (uintptr_t i)       { return offset(0x200)[i]; }
    volatile       uint32_t& UNPEND(uintptr_t i)       { return offset(0x280)[i]; }
    volatile const uint32_t& ACTIVE(uintptr_t i) const { return offset(0x300)[i]; }
    volatile       uint32_t& PRI   (uintptr_t i)       { return offset(0x400)[i]; }
    volatile       uint32_t& SWTRIG(void)              { return offset(0xF00)[0]; }
}* const NVIC = reinterpret_cast<LM3S_NVIC*>(0xE000E000);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM