我想在某种结构中使用标志,让我们说:
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代码。
因为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
现在将包含所有标志。如果您希望可以将其解释为常规整数。
当flag4
为1且flag3
为1时,flag4 << 1
为10(十进制为2),因为您向左移动1。使用|
,你可以添加flag3
,它不会移动,所以你有11(十进制3)。
当flag3
为0时它会做同样的事情,但结果是10(十进制2)因为flag3
为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不是可移植的。您可能必须重新运行标志才能获得最佳结果(最短/最快装配)。
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书