将数字映射到C中的位位置

Tom*_*ogi 2 c serial-communication bit-fields

我正在开发一个在Atmel AT90CAN128上运行的程序.连接到该控制器有40个设备,每个设备都具有状态(开/关).由于我需要通过串行通信向PC报告每个设备的状态,因此我有40位,用于定义设备是打开还是关闭.此外,PC可以打开或关闭任何此设备.

所以,我的第一次尝试是创建以下结构:

typedef struct {
     unsigned char length;      //!< Data Length
     unsigned data_type;        //!< Data type
     unsigned char data[5];     //!< CAN data array 5 * 8 = 40 bits
} SERIAL_packet;
Run Code Online (Sandbox Code Playgroud)

这个问题是PC会发送一个unsigned char address告诉我设备打开/关闭,所以访问对应于该address数字的位变得相当复杂......

所以我开始寻找选项,我偶然发现了C99 _Bool类型.我想,很好,现在我只是创建一个_Bool data[40],我可以address通过索引我的data数组访问该位.事实证明,在C(或C++)中,内存映射需要一个完整的字节来寻址它.所以,即使我声明_Bool的是,大小_Bool将是8位这是一个问题(它需要尽可能快地让更多的比特我送较慢它获取,而电脑将specting 40位),而不是非常有效的沟通.所以我开始研究Bit Fields,并尝试了以下方法:

typedef struct {
    unsigned char length;   //!< Data Length
    unsigned data_type;     //!< Data type
    arrayData data[40]; //!< Data array 5 bytes == 40 bits
} SERIAL_packet;

typedef struct {
    unsigned char aux : 1;
} arrayData;
Run Code Online (Sandbox Code Playgroud)

我想知道,这是否会将其映射data[40]到一个大小为40位(5字节)的后续内存块?

如果没有,我有什么明显的解决方案吗?这似乎不是一件非常复杂的事情(如果设备少于32个,那么我会使用a int并通过位掩码进行访问会更简单).

dbu*_*ush 5

假设您返回的地址在0 - 39范围内且a char有8位,您可以将data数组视为位数组:

| data[0]                       | data[1]                           ...
-----------------------------------------------------------------
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11| 12| 13| 14| 15|
-----------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

设置位i:

packet.data[i/8] |= (1 << (i%8));
Run Code Online (Sandbox Code Playgroud)

清除位i:

packet.data[i/8] &= (1 << (i%8)) ^ 0xff;
Run Code Online (Sandbox Code Playgroud)

阅读比特i:

 int flag = (packet.data[i/8] & (1 << (i%8)) != 0;
Run Code Online (Sandbox Code Playgroud)