我可以将多个位域结构替换为 C 中的数组吗?

Can i replace multiple bitfield structs as an array in C?

我正在开发一个带有 CAN 通信的微控制器,它有 32 个通信邮箱。 在制造商提供的头文件中,他们有以下声明:

struct CANMSGID_BITS {    // bits  description
   Uint16 EXTMSGID_L:16;  // 15:0
   Uint16 EXTMSGID_H:2;   // 17:16
   Uint16 STDMSGID:11;    // 28:18
   Uint16 AAM:1;          // 29
   Uint16 AME:1;          // 30
   Uint16 IDE:1;          // 31
};

/* Allow access to the bit fields or entire register */
union CANMSGID_REG {
   Uint32               all;
   struct CANMSGID_BITS bit;
};

/* eCAN Message Control Register (MSGCTRL) bit definitions */
struct CANMSGCTRL_BITS {  // bits  description
   Uint16 DLC:4;          // 3:0
   Uint16 RTR:1;          // 4
   Uint16 rsvd1:3;        // 7:5   reserved
   Uint16 TPL:5;          // 12:8
   Uint16 rsvd2:3;        // 15:13 reserved
   Uint16 rsvd3:16;       // 31:16 reserved
};

/* Allow access to the bit fields or entire register */
union CANMSGCTRL_REG {
   Uint32                  all;
   struct CANMSGCTRL_BITS  bit;
};

/* eCAN Message Data Register low (MDR_L) word definitions */
struct CANMDL_WORDS {    // bits  description
   Uint16 LOW_WORD:16;   // 15:0
   Uint16 HI_WORD:16;    // 31:16
};

/* eCAN Message Data Register low (MDR_L) byte definitions */
struct CANMDL_BYTES {  // bits   description
   Uint16 BYTE3:8;     // 7:0
   Uint16 BYTE2:8;     // 15:8
   Uint16 BYTE1:8;     // 23:16
   Uint16 BYTE0:8;     // 31:24
};

/* Allow access to the bit fields or entire register */
union CANMDL_REG {
   Uint32              all;
   struct CANMDL_WORDS word;
   struct CANMDL_BYTES byte;
};

/* eCAN Message Data Register high  (MDR_H) word definitions */
struct CANMDH_WORDS {     // bits  description
   Uint16 LOW_WORD:16;    // 15:0
   Uint16 HI_WORD:16;     // 31:16
};

/* eCAN Message Data Register low (MDR_H) byte definitions */
struct CANMDH_BYTES {  // bits   description
   Uint16 BYTE7:8;     // 7:0
   Uint16 BYTE6:8;     // 15:8
   Uint16 BYTE5:8;     // 23:16
   Uint16 BYTE4:8;     // 31:24
};

/* Allow access to the bit fields or entire register */
union CANMDH_REG {
   Uint32              all;
   struct CANMDH_WORDS word;
   struct CANMDH_BYTES byte;
};

struct MBOX {
   union CANMSGID_REG   MSGID;
   union CANMSGCTRL_REG MSGCTRL;
   union CANMDL_REG     MDL;
   union CANMDH_REG     MDH;
};

这是针对单个邮箱的,但是有 32 个邮箱,因此邮箱的定义如下:

struct ECAN_MBOXES {
   struct MBOX MBOX0;
   struct MBOX MBOX1;
   struct MBOX MBOX2;
   .
   .
   .
   struct MBOX MBOX30;
   struct MBOX MBOX31;
}; 

最后我们有:

extern volatile struct ECAN_MBOXES ECanaMboxes;

其中 'ECanaMboxes' 在链接器命令文件中定义。

我只用以下声明替换了 struct ECAN_MBOXES

struct ECAN_MBOXES {
    struct MBOX MBOX[32];
};

这是一个有效的更改,还是我们不允许从位域中创建数组? 我已经尝试了两种方式的代码,并且无论哪种方式,代码都运行良好。我更喜欢数组,因为它更容易为特定目的访问特定邮箱,而且所有邮箱的配置可以迭代方式完成。我想知道声明结构体会不会引起什么意外问题?

更改应该没问题,位域在数组中不是特例。

请注意,您需要保留原始代码中该结构 volatile 的实际变量声明。

至于ECAN_MBOXES,考虑改用联合:

typedef union {
   struct                 // C11 anonymous struct
   {
     struct MBOX MBOX0;
     struct MBOX MBOX1;
     ...
   };
   struct MBOX MBOX[32];
}ECAN_MBOXES ; 

现在如果你有 ECAN_MBOXES foo,你可以用 foo.MBOX0foo.MBOX[0] 访问它,它指的是同一个邮箱寄存器。

struct ECAN_MBOXES 是否包含 32 个不同的 struct MBOX 实例或 32 个 struct MBOX 的数组与 struct MBOX 的内部布局方式无关。

后者显然更可取,因为您可以索引数组,但它不会破坏 struct MBOX 的任何内容,无论它是否包含联合和位域。

请注意,您实际上并不是在创建一个位域数组,而是一个包含位域的结构数组。实际的位域数组不是合法的构造,如果您尝试这样做,您的编译器会给您一个错误。