位字段

可以使用简单的位字段来描述可能涉及特定位数的事物。

struct encoderPosition {
   unsigned int encoderCounts : 23;
   unsigned int encoderTurns  : 4;
   unsigned int _reserved     : 5;
};

在这个例子中,我们考虑一个具有 23 位单精度和 4 位来描述多圈的编码器。当与输出与特定位数相关联的数据的硬件接口时,经常使用位字段。另一个例子可能是与 FPGA 通信,其中 FPGA 以 32 位部分将数据写入存储器,允许硬件读取:

struct FPGAInfo {
    union {
        struct bits {
            unsigned int bulb1On  : 1;
            unsigned int bulb2On  : 1;
            unsigned int bulb1Off : 1;
            unsigned int bulb2Off : 1;
            unsigned int jetOn    : 1;
        };
        unsigned int data;
   };
};

在这个例子中,我们展示了一个常用的构造,能够访问各个位的数据,或者整个数据包的写入(模拟 FPGA 可能做的事情)。然后我们可以访问这样的位:

FPGAInfo fInfo;
fInfo.data = 0xFF34F;
if (fInfo.bits.bulb1On) {
    printf("Bulb 1 is on\n");
}

这是有效的,但根据 C99 标准 6.7.2.1,第 10 项:

单元内的位域分配顺序(高阶到低阶或低阶到高阶)是实现定义的。

以这种方式定义位域时,你需要注意字节序。因此,可能需要使用预处理程序指令来检查机器的字节顺序。一个例子如下:

typedef union {
    struct bits {
#if defined(WIN32) || defined(LITTLE_ENDIAN)
    uint8_t commFailure :1;
    uint8_t hardwareFailure :1;
    uint8_t _reserved :6;
#else
    uint8_t _reserved :6;
    uint8_t hardwareFailure :1;
    uint8_t commFailure :1;
#endif
    };
    uint8_t data;
} hardwareStatus;