我想在某些结构中使用标志,让我们说:
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代码。
答案 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书