在 C 中提取 16 位联合中的位位置

Extracting bit positions in a union of 16 bits in C

我想在C中声明一个union,主要包含一个16-bit字,我应该可以read/write LSP 7 bits8th bit 分别用于 16-bit 字中的每个字节,所以我声明如下:

typedef union {
    uint8_t full_8_char_byte[2];
    uint8_t ascii_7_bits_word_0 : 7; /* another way of representing LSP 7 ASCII bits */
    uint8_t parity_bit_word_0 : 1;   /* another way of representing MSP parity bit */
    uint8_t ascii_7_bits_word_1 : 7; /* another way of representing LSP 7 ASCII bits */
    uint8_t parity_bit_word_1 : 1;   /* another way of representing MSP parity bit */
} ip_char_t;

现在,当我将 7-bit 值写入 16-bit 字中的这些单独字节时:

x.full_8_char_byte[0] = 0x7E;
x.full_8_char_byte[1] = 0x7E;

下面的简单程序:

int main()
{
    ip_char_t x;
    x.full_8_char_byte[0] = 0x7E;
    x.full_8_char_byte[1] = 0x7E;

    printf("%c   %c\n", x.full_8_char_byte[1], x.full_8_char_byte[0]);
    printf("%u   %u\n", x.full_8_char_byte[1], x.full_8_char_byte[0]);
    printf("%X   %X\n\n", x.full_8_char_byte[1], x.full_8_char_byte[0]);

    printf("%c   %c\n", x.ascii_7_bits_word_1, x.ascii_7_bits_word_0);
    printf("%u   %u\n", x.ascii_7_bits_word_1, x.ascii_7_bits_word_0);
    printf("%X   %X\n\n", x.ascii_7_bits_word_1, x.ascii_7_bits_word_0);

    printf("%d   %d\n", x.parity_bit_word_1, x.parity_bit_word_0);
    return 0;
}

给出正确的输出如下:

~   ~  
126   126   
7E   7E

~   ~ 
126   126 
7E   7E

0   0

但是当我初始化时x.full_8_char_byte[1] to a 8-bit value:

x.full_8_char_byte[0] = 0x7E;
x.full_8_char_byte[1] = 0xFF;

我得到的输出是:

�   ~ 
255   126 
FF   7E

~   ~ 
126   126 
7E   7E

0   0

当我初始化 x.full_8_char_byte[0] to 0xFF 时发生了类似的事情,我的问题是为什么 x.ascii_7_bits_word_1x.parity_bit_word_1 中的值没有反映在 x.full_8_char_byte[1] 中的每个变化?

看着这个:

typedef union {
    uint8_t full_8_char_byte[2];
    uint8_t ascii_7_bits_word_0 : 7; /* another way of representing LSP 7 ASCII bits */
    uint8_t parity_bit_word_0 : 1;   /* another way of representing MSP parity bit */
    uint8_t ascii_7_bits_word_1 : 7; /* another way of representing LSP 7 ASCII bits */
    uint8_t parity_bit_word_1 : 1;   /* another way of representing MSP parity bit */
} ip_char_t;

评论建议您期望 4 个位域成员映射第一个数组成员的位。那行不通,因为 unionall 成员是可选的可能内容,这也意味着每个成员都将放在最开始。你可能想写的是

typedef union {
    uint8_t full_8_char_byte[2];
    struct {
        uint8_t ascii_7_bits_word_0 : 7; /* another way of representing LSP 7 ASCII bits */
        uint8_t parity_bit_word_0 : 1;   /* another way of representing MSP parity bit */
        uint8_t ascii_7_bits_word_1 : 7; /* another way of representing LSP 7 ASCII bits */
        uint8_t parity_bit_word_1 : 1;   /* another way of representing MSP parity bit */
    };
} ip_char_t;

所以这个联合可以或者包含你的数组或者一个带有位域的结构。


请注意,这并不能以可移植的方式解决您的问题:对于您的位域的排列方式没有严格的保证,请参阅 Leushenko 的评论以了解详细信息!为了方便地解决这个问题,您可以提供宏来访问各个位,例如

typedef uint8_t ip_char_t[2];

#define ascii_7_bits_word(x,i) ((x)[i] & 0x7f)
#define parity_bit_word(x,i) ((x)[i] >> 7)

或者,如果您还需要写入位或想要强制执行类型安全,请改为编写(内联)函数。