铸造时如何将连续的位域转换为变量

时间:2019-04-04 12:33:10

标签: c casting structure data-conversion bit-fields

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

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'mode'为3

如果flag4 == 1和flag3 == 0'mode'为2 等

我的问题是:为什么?我希望它能起作用,但是我不知道为什么。

我在Atollic工作,用于STM32代码。

4 个答案:

答案 0 :(得分:1)

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

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

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

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

flagfield现在将包含所有标志。如果愿意,可以将其解释为正整数。

答案 1 :(得分:0)

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

flag3为0时,它执行相同的操作,但结果为10(十进制2),因为flag3为0。

答案 2 :(得分: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的调用约定中,标志3和标志4在内存中的顺序是分开的,因此标志34不那么可移植。您可能需要重新标记以获取最佳结果(最短/最快的汇编)。

答案 3 :(得分: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'mode'为3

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

您需要一本好的初学者C书