2012-12-25 21 views
13

考慮以下幾點:在C++中的布爾乘法?

inline unsigned int f1(const unsigned int i, const bool b) {return b ? i : 0;} 
inline unsigned int f2(const unsigned int i, const bool b) {return b*i;} 

f2語法是更緊湊,但該標準保證f1f2是完全等同?

此外,如果我希望編譯器優化這個表達式,如果bi在編譯時已知,我應該選擇哪個版本?

+2

您無法知道「編譯器」將如何使用表達式(在編譯時間已知參數的情況下)執行哪些操作,而無需指定哪種編譯器,但可能會優化兩者。一種方法可以告訴,用編譯時間已知的參數進行編譯並檢查輸出。 –

+1

查看生成的彙編代碼 – James

+1

FWIW,MSVC爲第一種情況生成一個掩碼並添加,第二個爲一個乘法,在我阻止它使用布爾值本身的評估操作的情況下(如果可以的話,它爲了進一步優化將改變生產布爾的測試)。從本質上講,無論是哪種情況,MSVC都是無分支的,在天真的情況下似乎更加優化。 – JasonD

回答

11

嗯,是的,兩者都是相同的。 bool是一個整數類型,true保證在整數上下文中轉換爲1,而false保證轉換爲0

(反過來也是如此,即非零整數值,保證轉換爲true在布爾上下文,而零個整數值,保證轉換爲false在布爾上下文中)。

既然你工作無符號的類型,可以很容易地想出其他的,可能是位劈基於同樣的事情還沒有完全便攜式的實現,如

i & -(unsigned) b 

雖然一個體面的編譯器應該能夠通過自身的選擇最好的實現你的任何版本。

P.S.儘管令我非常吃驚的是,GCC 4.1.2幾乎從字面上編譯了所有三種變體,即它在基於乘法的變體中使用了機器乘法指令。在?:變體上使用cmovne指令可以非常聰明地使它無分支,這很可能使它成爲最有效的實現。

1

編譯器將使用隱式轉換從b作出unsigned int,所以,是的,這應該工作。您正在通過簡單乘法跳過條件檢查。哪一個更有效/更快?不知道。一個好的編譯器很可能會優化我假設的兩個版本。

5

是的。它是安全的假設true1和表達式時,你做的,是保證false0

C++ 11,積分促銷,4.5

bool類型的右值可以被轉換爲類型爲int的右值,其中 虛假成爲零,並且真正成爲一個。

0

FWIW,下面的代碼

inline unsigned int f1(const unsigned int i, const bool b) {return b ? i : 0;} 
inline unsigned int f2(const unsigned int i, const bool b) {return b*i;} 

int main() 
{ 
    volatile unsigned int i = f1(42, true); 
    volatile unsigned int j = f2(42, true); 
} 

用gcc編譯-02生產該組件:

.file "test.cpp" 
    .def ___main; .scl 2; .type 32; .endef 
    .section .text.startup,"x" 
    .p2align 2,,3 
    .globl _main 
    .def _main; .scl 2; .type 32; .endef 
_main: 
LFB2: 
    .cfi_startproc 
    pushl %ebp 
    .cfi_def_cfa_offset 8 
    .cfi_offset 5, -8 
    movl %esp, %ebp 
    .cfi_def_cfa_register 5 
    andl $-16, %esp 
    subl $16, %esp 
    call ___main 
    movl $42, 8(%esp) // i 
    movl $42, 12(%esp) // j 
    xorl %eax, %eax 
    leave 
    .cfi_restore 5 
    .cfi_def_cfa 4, 4 
    ret 
    .cfi_endproc 
LFE2: 

沒有多少留下任何f1f2的,因爲你可以看到。

就C++標準而言,只要不改變可觀察行爲(就好像規則),編譯器就可以對優化做任何事情。

+2

爲了產生一個有代表性的結果,你可能應該使用函數f1(rand(),rand())的非可預測的(通過編譯器)參數就是一個更好的例子。 – AnT