在“C”中的结构元素之间手动插入填充字节

siu*_*siu 2 c gcc struct bare-metal memory-alignment

我有一组用于嵌入式应用程序(ARM 裸机)中的外设的 32 位寄存器,具有以下字节地址。

CTL 0x0;
STAT 0x4
TXR 0x8 <-- 不连续地址
RXR 0x20
DAT1 0x30 <-- 不连续地址
DAT2 0x40 <-- 不连续地址
等等

我想将所有这些寄存器分组到一个 C 结构中(它是一个打包结构)

struct my_peri {
     uint32_t CTL;
     uint32_t STAT;
     uint32_t TXR;
     uint32_t RXR;
     uint32_t DAT1;
     uint32_t DAT2;
};

struct my_peri* pPeri0 = (uint32_t*) (BASE_ADDRESS_OF_MY_PERI_0);
Run Code Online (Sandbox Code Playgroud)

现在如果我访问

pPeri->RXR;  // This will point to (BASE_ADDRESS + 0x10)
             // But the actual address i want to refer is (BASE_ADDRESS + 0x20)
Run Code Online (Sandbox Code Playgroud)

为了获得正确的地址,我在之间手动添加了一些元素

struct my_peri {
     uint32_t CTL;
     uint32_t STAT;
     uint32_t TXR;
     uint32_t RESERVED[4]; // 0x10 to 0x1c
     uint32_t RXR;
     uint32_t RESERVED_1[3]; // 0x24-0x2c
     uint32_t DAT1;
     uint32_t RESERVED_2[3]; // 0x34-0x3c
     uint32_t DAT2;
};
Run Code Online (Sandbox Code Playgroud)

但根据外设规格,对 RESERVED、RESERVED_1 和 RESERVED_2 的任何访问都会给出错误。

Is there a way to add address spacing between the struct elements?
Without adding RESERVED elements

If not, is there a way to group these registers into a single data structure?.
With each register pointing to the right address.
Run Code Online (Sandbox Code Playgroud)

我正在使用 ARM-GCC 工具链。

Joh*_*nck 5

是的,您可以使用“位字段”在结构中创建未命名字段:

struct my_peri {
     uint32_t CTL;
     uint32_t STAT;
     uint32_t TXR;
     uint32_t : 32;
     uint32_t RXR;
     uint32_t : 32;
     uint32_t : 32;
     uint32_t : 32;
     uint32_t DAT1;
     uint32_t : 32;
     uint32_t : 32;
     uint32_t : 32;
     uint32_t DAT2;
};
Run Code Online (Sandbox Code Playgroud)

不幸的是没有数组语法;如果需要,您可以通过将类型更改为 uint64_t 来折叠 to:32对。:64

另一种方法是,如果您的字段与本示例中的类型相同,则可以将整个事物视为整数数组,并使用enum { CTL = 0, STAT = 1, TXR = 2, RXR = 4, ... }.