2013-02-05 56 views
0

我已經看到了兩種不同的方式來處理組合位移和掩碼,並且想知道如果它們是等價的,假設結果被用作布爾值,或者如果問題比其他問題更少或性能更好。執行位移和掩碼的最高性能/正確方式是什麼?

兩個:

flags & (BIT_MASK << BIT_NUMBER)

(flags >> BIT_NUMBER) & BIT_MASK

前者好像它可能對視flags大小一些平臺的問題,即位移位可能會推將掩碼放在臨時變量的頂部。這是一個問題嗎?升檔與降檔有任何性能差異嗎?

BIT_MASKBIT_NUMBER合併成一個明確的掩碼再次讓我感覺更好,但我正在處理遺留代碼,我希望儘量減少對其的更改。

+3

拋開溢出問題,它們在功能上並不等效(除非結果使用布爾值)。 – NPE

+0

好的結果 - 是的,我將結果用作布爾值。編輯該。 – dlanod

+0

我很確定兩個替代方案使用兩條指令,所以它們是相同的。 –

回答

1

如果BIT_MASKBIT_NUMBER是常量,編譯器可能會預先計算表達式,並在將它們組合在一起時保存指令。這有利於第一種方法。

如果您嘗試獲取多個位,您需要將結果向右移動。這有利於第二種方法。

+0

我不認爲有關於它的任何「可能」。給定兩個常量值的算術運算,即使在調試模式下,編譯器也會在編譯時計算結果。該語言的許多部分都要求這樣做。 (例如'const int X = 1 + 1;'不能導致代碼在運行時執行) – StilesCrisis

+0

爲什麼獲得多於一位有利於第二位? – dlanod

+1

@dlanod,因爲您可能想要將結果評估爲數字而不是布爾值。 –

1

flags & (BIT_MASK << BIT_NUMBER)可以在一個位和指令中完成。

(flags >> BIT_NUMBER) & BIT_MASK需要兩個指令,一個移位後跟一個位和。

(實際上,在PowerPC,第二個版本也有一個專門的操作碼,rlwinm,但英特爾並沒有這樣的運氣。)

最大的不同,當然,是他們產生不同的結果值。如果你只是檢查零或非零,那麼我更喜歡第一個版本,因爲它是單個指令。

0

我建議你不要考慮編譯器後端可能做什麼,如果你沒有使用優化,那麼它並不重要,如果你使用優化,那麼任何好的編譯器都會做正確的事情儘可能少地爲您的編譯目標指示。

從語義上來看語義上的含義。例如,如果標記類型爲uint64_t,並且BIT_NUMBER大於31,則只有第二個表單可能會按照您的意圖進行。原因是(BIT_MASK << BIT_NUMBER)將被評估爲int,可能是32位,並且因爲BIT_NUMBER大於31將評估爲零,因此整個事情將在AND之後產生零。另一方面,(flags >> BIT_NUMBER)將被評估爲64位表達式(因爲標誌是64位),並且在進行AND之前將被正確地移位。

對於一個有趣的談鏘編譯器看到Clang: Defending C++ from Murphy's Million Monkeys這將顯示您的語義理解可能在今天的編譯器的深處,在分鐘21:25特定的外觀既解決了,我是指上述C++整數運算規則的細微差別。這是在講

static const long long DiskCacheSize = 8 << 30; // 8 Gigs 

Clang gives: 

% clang++ -std=c++11 -fsyntax-only overflow.cpp 
overflow.cpp:1:42: warning: signed shift result (0x200000000) requires 35 
bits to represent, but 'int' only has 32 bits [-Wshift-overflow] 
static const long long DiskCacheSize = 8 << 30; // 8 Gigs 
             ~^~~ 

最近我很驚訝地得知,GCC和Java JIT編譯器非常聰明,明白,一個組的變化,口罩,和ORS的基本上是做一個32的旋轉使用的示例例如,位數量,並將生成旋轉指令,請參閱Are bitwise rotations slower than shifts on current Intel CPU?。編譯器這些日子非常好。

相關問題