2015-11-21 36 views
2

我很難理解爲什麼要在枚舉的 中使用按位運算,然後在代碼中使用。 爲什麼不使用只是數字或布爾的 例如:爲什麼在C++中使用按位運算

enum 
{ 
    RS_BLEND = (1 << 0), 
    RS_BLEND_FUNC = (1 << 1), 
    RS_CULL_FACE = (1 << 2), 
    RS_DEPTH_TEST = (1 << 3), 
    RS_DEPTH_WRITE = (1 << 4), 
    RS_DEPTH_FUNC = (1 << 5), 
    RS_CULL_FACE_SIDE = (1 << 6), 
//   RS_STENCIL_TEST = (1 << 7), 
//   RS_STENCIL_WRITE = (1 << 8), 
//   RS_STENCIL_FUNC = (1 << 9), 
//   RS_STENCIL_OP = (1 << 10), 
    RS_FRONT_FACE = (1 << 11), 

    RS_ALL_ONES = 0xFFFFFFFF, 
}; 


void RenderState::StateBlock::setCullFace(bool enabled) 
{ 
    _cullFaceEnabled = enabled; 
    if (!enabled) 
    { 
     _bits &= ~RS_CULL_FACE; 
    } 
    else 
    { 
     _bits |= RS_CULL_FACE; 
    } 
} 

這並不重要或嵌入式軟件。

+1

它被用作[位域](https://en.m.wikipedia.org/wiki/Bit_field)。 –

+0

你會怎麼寫呢? –

回答

4

使用位而不是布爾值的優點是您可以直接操作值集。例如定義:

const int FILLED = (1 << 0); 
const int STROKED = (1 << 1); 
const int SHADOW = (1 << 2); 
const int BLINK = (1 << 3); 

可以有一個函數接受draw_mode參數並調用它像

draw_symbol(FILLED | SHADOW | BLINK, "X"); 

即直接傳遞的值的子集。

使用容器而不是單個整數參數將需要更多的代碼來編寫和讀取。這也會效率較低,但在某些情況下,這不是最重要的一點。

1

這些枚舉值是所謂的標誌用於位域(這裏是_bits)。類似的行爲可以通過聲明布爾型的結構來獲得:

struct field { 
    bool rs_blend; 
    bool rs_blend_func; 
    ... 
}; 

然而,這樣的結構將需要每個條目至少一個字節,將難於操作,因此開發者採取了不同的方法,通過編碼這些值轉換成整數值的位。

的值1的任意整數具有「最右邊的」(至少顯著)位設置,因此1 << i具有完全i個比特等於1,這意味着在該枚舉(RS_BLENDRS_BLEND_FUNC)每隔一定編碼一個位。這實際上是一個相當常見的習慣用法,特別是在處理結構更加冗長的C語言中。

通過使用按位操作等可以在此位域立即設置或清除。例如,RS_BLEND | RS_BLEND_FUNC會創建一個具有這兩個標誌集的位域。請參閱this線程以獲取有關在此上下文中使用按位運算的詳細信息。

0

如果您使用布爾值,則需要1位與8位。使用1/8的內存是一個相當驚人的儲蓄來代表完全相同的數據(使用8倍多,只是因爲有人爲位操作不舒服同樣令人難以置信的浪費),如果你用熱數據處理頻繁,可以不管在一個循環中訪問(我的i7中,每個L1緩存的核心只有64KB,例如,更不用說有限的寄存器)。另外,如果你在這裏使用位,你可以用一條指令測試兩個或更多的位。您也可以一次全部使用FFZ/FFS高效地找到64位中的空閒位或置位位。您可以輕鬆地反轉,說,64位在同一時間,而不是通過64個布爾循環,不得不做一次一個是不是CPU只難以置信的高效率,也少了效率和生產力爲開發者的所有寫該代碼當他可以只使用一個運營商。

好處在繼續。我其實認爲更多的人應該使用按位操作,而不是更少。需要一些時間來習慣以位來思考,但這不需要太長時間。

0

它很方便。

在示例代碼中,顯然(包括評論中的內容)至少有12個不同的設置,每個設置都打開或關閉,但可以組合打開或關閉。

位擺動允許打開或關閉各個設置(包括一個組)的組,或者測試特定組是否打開或關閉,而無需大驚小怪。

數字值和數字操作可以做到這一點,但不是那麼方便。

例如,它更容易(且不易出錯),以測試的CULL_FACE和DEPTH_FACE設置的至少一個是通過使用

if (flags & (RS_CULL_FACE | RS_DEPTH_FACE)) 

比它是保持所有可能數值的軌道對於這兩個設置可能是真實的,並對每一個進行測試。