简体   繁体   English

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

[英]Manually insert padding bytes between the struct elements in 'C'

I have a set of 32-bit registers for a peripheral in an embedded application(ARM bare-metal), with the following byte addresses.我有一组 32 位寄存器用于嵌入式应用程序(ARM 裸机)中的外围设备,具有以下字节地址。

CTL 0x0; CTL 0x0;
STAT 0x4状态 0x4
TXR 0x8 <-- Discontinuous address TXR 0x8 <-- 不连续地址
RXR 0x20接收器 0x20
DAT1 0x30 <-- Discontinuous address DAT1 0x30 <-- 不连续地址
DAT2 0x40 <-- Discontinuous address DAT2 0x40 <-- 不连续地址
and so on等等

I want to group all these registers into a C struct (Its a packed struct)我想将所有这些寄存器分组到一个 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);

Now if i access现在如果我访问

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

In order to get the right the address right i manually added some elements between为了获得正确的地址,我手动添加了一些元素

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

But any access to RESERVED, RESERVED_1 and RESERVED_2 will give error as per the peripheral specs.但是任何对 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.

I'm using ARM-GCC toolchain.我正在使用 ARM-GCC 工具链。

Yes, you can create unnamed fields within a struct using "bit fields":是的,您可以使用“位字段”在结构中创建未命名字段:

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

Unfortunately there's no array syntax;不幸的是,没有数组语法; you can collapse pairs of :32 to :64 if you want by changing the type to uint64_t.如果需要,您可以通过将类型更改为 uint64_t 来折叠:32:64对。

An alternative, if your fields are all the same type as in this example, would be to treat the whole thing as an array of integers and index into it using an enum { CTL = 0, STAT = 1, TXR = 2, RXR = 4, ... } .另一种方法是,如果您的字段与本示例中的所有字段类型相同,则将整个事物视为整数数组,并使用enum { CTL = 0, STAT = 1, TXR = 2, RXR = 4, ... }

To answer both your questions, You will inevitably end up with some kind of fake padding element as C has no provision to force a particular layout for a struct.要回答你的两个问题,你将不可避免地得到某种假的填充元素,因为 C 没有规定强制结构的特定布局。

However perhaps a nicer way of achieving this given you ultimately have a sparse layout would be to use a struct full of of pointers.但是,考虑到您最终拥有稀疏布局,实现这一点的更好方法可能是使用一个充满指针的结构。 This no longer restricts you as to layout in any way and in most cases if you define the pointers as const gcc will optimize out the dereference completely and should even optimize out the whole array.这不再以任何方式限制您的布局,并且在大多数情况下,如果您将指针定义为 const gcc 将完全优化取消引用,甚至应该优化整个数组。 I admit this is not exactly what you asked for but I think it is still a good way of solving the problem.我承认这不完全是您所要求的,但我认为这仍然是解决问题的好方法。 You are also no longer relying on a C extension and hoping the compiler respects your packing and layout requirements.您也不再依赖 C 扩展并希望编译器尊重您的打包和布局要求。

#include <stdio.h>
#include <stddef.h>
#include <inttypes.h>

struct my_peri {
     uint32_t CTL;
     uint32_t STAT;
     uint32_t TXR;
     uint32_t RXR __attribute__((aligned (32)));
     uint32_t DAT1 __attribute__((aligned (16)));
     uint32_t DAT2 __attribute__((aligned (16)));
};

int main(void)
{
     printf("RXR  @%x\n", (unsigned) offsetof(struct my_peri, RXR));
     printf("DAT1 @%x\n", (unsigned) offsetof(struct my_peri, DAT1));
     printf("DAT2 @%x\n", (unsigned) offsetof(struct my_peri, DAT2));
     return 0;
}

Output:输出:

RXR  @20
DAT1 @30
DAT2 @40

Note that aligned values have to be powers of two.请注意, aligned值必须是 2 的幂。 But that works out here.但这在这里行得通。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM