在转换时如何将连续的位字段转换为变量

问题描述 投票:0回答:4

我想在某种结构中使用标志,让我们说:

struct {
    flag1:1;
    flag2:1;
    flag3:1;
    flag4:1;
}Flags;

标志3和4描述了我的目标项目现在的模式。我想将标志转换为数字,以读取flag3和flag4中设置的内容。我所做的是:

uint8_t mode;
mode = ( ((uint8_t)Flags.flag4 << 1) | (uint8_t)Flags.flag3) );

这让我感到惊讶:

如果flag4 == 1并且flag3 == 1'模式'是3

如果flag4 == 1并且flag3 == 0'模式'是2等。

我的问题是:为什么?我这样做是希望它有效,但我不知道为什么。

我在Atollic工作STM32代码。

c casting structure data-conversion bit-fields
4个回答
1
投票

因为flag4和flag3将被解释为二进制数字中的数字。 flag4将是最重要的。

Flags.flag4 << 1将bitshift flag4向左移动,因此如果flag4为1,则结果为10.然后我们执行逻辑或使用flag3。如果flag3为1,则将产生11,即二进制为3。

这是一个可以解释它的小循环。假设我们在数组中有8个标志,int flags[8]。现在我们要将这些压缩成uint8_t flagfield。这可以通过这个循环来完成:

flagfield=0;
for(int i=0; i<8; i++)
    flagfield |= (uint8_t)(flags[i] << i);

flagfield现在将包含所有标志。如果您希望可以将其解释为常规整数。


0
投票

flag4为1且flag3为1时,flag4 << 1为10(十进制为2),因为您向左移动1。使用|,你可以添加flag3,它不会移动,所以你有11(十进制3)。

flag3为0时它会做同样的事情,但结果是10(十进制2)因为flag3为0。


0
投票

让我们剖析代码:

mode =(((uint8_t)Flags.flag4 << 1)|(uint8_t)Flags.flag3));

第一:

(uint8_t)Flags.flag4
(uint8_t)Flags.flag3

Flags.flag4和Flags.flag3被转换为uint8_t。这部分很重要。虽然Flags.flag4和Flags.flag3只有一位,但是转换为完整的8位。

下一个:

((uint8_t)Flags.flag4 << 1)

这将flag4的值向左移位1位。它和x * 2一样。记住,演员把它变成了一个完整的8位。所以转变不会溢出。 flag4只能是0或1所以在移位后这是0或2。

最后,这两个值是一起存储的。根据flag3和flag4的值,结果为0-3。

请注意另一种写入此方法的方法,尽管要使用架构/ ABI

struct {
    uint8_t flag1:1;
    uint8_t flag2:1;
    union {
        struct {
            uint8_t flag3:1;
            uint8_t flag4:1;
        };
        uint8_t flag34:2;
    };
} Flags;

在架构/ ABI的调用约定中,命令flag3和flag4在内存中是sepcified,因此flag34不是可移植的。您可能必须重新运行标志才能获得最佳结果(最短/最快装配)。


0
投票

mode = ( ((uint8_t)Flags.flag4 << 1) | (uint8_t)Flags.flag3) );

什么时候:

如果flag4 == 1且flag3 == 0'mode'为2

说明:

Flags.flag4 == 1
1 << 1 == 2
2 | 0 == 2

如果flag4 == 1并且flag3 == 1'模式'是3

Flags.flag4 == 1
1 << 1 == 2
2 | 1 == 3

你需要一本优秀的初学者C书

© www.soinside.com 2019 - 2024. All rights reserved.