2012-11-07 48 views
4

這是常見的執行檢查,並設置/清除標誌,如:從布爾用設定一個位掩碼快速路

if (some_test) { 
    flag |= SOME_FLAG; 
} 
else { 
    flag &= ~SOME_FLAG; 
} 

對此的一種方便的方式,我發現迄今...

flag = (some_test) ? (flag | SOME_FLAG) : (flag & ~SOME_FLAG); 

這可以被製作成宏及其確定,但有一些位twiddeling魔術以避免引用標誌兩次?

(如果flag的多個實例導致開銷)

的什麼我正在尋找(如果C可以在運營商做三元操作),是

例...

flag ((some_test) ? (|=) : (&= ~) SOME_FLAG; 

上面的例子僅是形容什麼,我找的當然,它不會以目前的形式工作。

回答

8
flag |= SOME_FLAG 

是一個表達式,所以你可以使用宏

#define SET_FLAG(flag, some_test) \ 
    ((some_test) ? ((flag) |= SOME_FLAG) : ((flag) &= ~SOME_FLAG)) 

,其評價flag只有一次,當你使用它,你需要輸入flag只有一次。

SET_FLAG(a->b->c->d, test); 
+0

謝謝,有道理,這看起來像最好的選擇。我想知道是否有掩碼操作符的某些組合可以做到這一點(只有一個操作符),但似乎沒有。 – ideasman42

+0

如果您考慮引入可變長度的位移(<< and >>)並檢測您的標誌是2的哪種功率......但這樣做沒有什麼好處,它更復雜,性能也更差。肯定不是一個簡潔的解決方案 – jheriko

3

我知道你不想兩次訪問標誌。但是你應該確定這是成本所在。通常,條件跳轉更爲昂貴。在最後的嵌入式處理器我的工作,最快的代碼將是這個樣子的:

flag &= ~(SOME_FLAG); 
flag |= (some_test!=0) * SOME_FLAG; 
+0

但是請注意,在許多常見平臺(x86,ppc,arm)上:編譯爲條件移動而不是分支 - 這可能比整數倍更便宜 – jheriko

0

如果要定義一個宏,並將它避免評估的面具,然後兩次,你可以做這樣的:

#define SETT(FLAG, MASK_T, MASK, TEST) \ 
do {\ 
    MASK_T mask = (MASK);\ 
    FLAG &= ~mask;\ 
    FLAG |= ((TEST) != 0) * mask;\ 
}\ 
while(false) 

#define SET(FLAG, MASK, TEST) SETT(FLAG, unsigned, MASK, TEST) 
+0

缺點是它會對FLAG進行多次寫入編譯器可能不會優化。 – ideasman42

+0

@ ideasman42條件將比一個額外的按位運算慢。 – Pubby

+0

也許(雖然條件可以評估到一個常數 - 也不一定) - 但你仍然可以評估一次,並應用一次按位運算 - 這裏給出的其他例子是這樣做的。 – ideasman42