[英]How consecutive bit-fields are converted to variable when casting
我想在某些結構中使用標志,可以這樣說:
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代碼。
因為flag4和flag3將被解釋為二進制數中的數字。 flag4將是最重要的。
Flags.flag4 << 1
會將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。
讓我們分析一下代碼:
模式=((((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不那么可移植。 您可能必須重新標記這些標志才能獲得最佳結果(最短/最快的匯編)。
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書
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.