在C语言中,指向需要访问字节指针列表的结构的指针

在C语言中,指向需要访问字节指针列表的结构的指针,c,C,首先,对标题感到抱歉,很难做出描述。我试图创建一个结构,将访问一个外设,它有相当多的内部寄存器,由3个地址线控制。因此,我有以下结构定义: typedef struct { union { unsigned char *reg0aPtr; unsigned char *reg0bPtr; } RegsAddrOffset0; union { unsigned char *reg1aPtr; unsigned char *reg1bPtr;

首先,对标题感到抱歉,很难做出描述。我试图创建一个结构,将访问一个外设,它有相当多的内部寄存器,由3个地址线控制。因此,我有以下结构定义:

typedef struct {
  union {
    unsigned char  *reg0aPtr;
    unsigned char  *reg0bPtr;
  } RegsAddrOffset0;

  union {
    unsigned char  *reg1aPtr;
    unsigned char  *reg1bPtr;
  } RegsAddrOffset1;

  ...

  union {
    unsigned char  *reg7aPtr;
    unsigned char  *reg7bPtr;
  } RegsAddrOffset7;
} DeviceRegMap;
那么如果我声明一个变量

DeviceRegMap  *uartRegMap = (DeviceRegMap *)(0xD0000000);
现在,如果我尝试使用uartRegMap变量访问内存映射寄存器,我想我会看到*(uartRegMap->RegsAddrOffset0.reg0aPtr)将从地址0xd000000读取数据,这是正确的。如果我使用*(uartRegMap->RegsAddrOffset1.reg1bPtr),我想我会访问0xD0000001,但它实际上是访问地址0xD0000004。由于处理器为32位,因此自然对齐为4字节。我在想,因为指针的大小是一个int,在本例中是32位,这就是我访问4字节地址范围(例如0xD0000000、0xD0000004、0xD0000008等)的原因

如果我声明了DeviceRegMap数据类型的一个实例,我希望进行以下初始化:

DeviceRegMap uartRegMap = {
  (unsigned char  *)0xD0000000,
  (unsigned char  *)0xD0000001,
  ...
  (unsigned char  *)0xD0000007,
};
然后,如果我想访问地址0xD0000007,那么我将使用*(uartRegMap.RegsAddrOffset7.reg7bPtr)

问题是为什么指向DeviceRegMap数据类型的指针在4字节对齐(例如0xD0000000、0xD0000004等)而不是字节对齐(例如0xD0000000、0xD0000001等)上访问内存。关于工具集,我正在使用Wind River diab编译器。谢谢

标记


编辑:根据abelenky的评论

大多数编译器都有一种方法来指示结构应该被紧密地打包,不需要为了对齐而填充

我不熟悉您的编译器,但可以在文档中查找类似的内容

#pragma pack

在结构定义之前。

如果要访问内存映射寄存器的字节大小部分,请执行以下操作:

struct DeviceRegMap {
  volatile unsigned char byte0;
  volatile unsigned char byte1;
  volatile unsigned char byte2;
  volatile unsigned char byte3;
};

static struct DeviceRegMap *device = (struct DeviceRegMap *)(0xD0000000);

现在
device->byte0
指向
0xd000000
,而
device->byte3
指向
0xd0000003
。这就是你想要的吗?

你的问题是什么?“我只是想确保我了解发生了什么。”这不是一个问题。你为什么要使用相同类型的两个项目的
联合体
?只是为了对正在发生的事情增加一些额外的见解。代码是由另一位工程师开发的,我继承了这段代码作为UART设备驱动程序。UART有大约21个不同的寄存器,这些寄存器通过内存映射的三条地址线进行访问。正如人们所指出的那样,工会确实是不必要的,但它们为代码的阅读增加了清晰度。例如,偏移量为0x00时,存在TX和RX保持寄存器以及一些其他寄存器。所以代码使用->RHR或->THR,这有助于可读性。罗兰,我认为这应该行得通。我将不得不等到我开始工作,在硬件上测试它。谢谢