考虑以下:
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
更紧凑,但标准是否保证f1
和f2
严格等价?
此外,如果我希望编译器在编译时b
和i
已知的情况下优化这个表达式,我应该更喜欢哪个版本?
考虑以下:
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
更紧凑,但标准是否保证f1
和f2
严格等价?
此外,如果我希望编译器在编译时b
和i
已知的情况下优化这个表达式,我应该更喜欢哪个版本?
嗯,是的,两者都是等价的。bool
是整数类型,true
保证1
在整数上下文中转换为,而false
保证转换为0
.
(反之亦然,即非零整数值保证true
在布尔上下文中转换为,而零整数值保证false
在布尔上下文中转换为。)
由于您使用的是无符号类型,因此可以轻松地提出其他可能基于 bit-hack 但完全可移植的同一事物的实现,例如
i & -(unsigned) b
尽管一个体面的编译器应该能够为您的任何版本自行选择最佳实现。
PS 虽然令我大吃一惊的是,GCC 4.1.2 实际上编译了所有三个变体,即它在基于乘法的变体中使用机器乘法指令。它足够聪明,可以cmovne
在变体上使用指令?:
使其无分支,这很可能使其成为最有效的实现。
是的。可以安全地假设true
is1
和false
is0
像你一样在表达式中使用并且得到保证:
C++11,整体促销,4.5:
bool 类型的右值可以转换为 int 类型的右值,false 变为 0,true 变为 1。
编译器将使用隐式转换来生成unsigned int
from b
,所以,是的,这应该可以工作。您通过简单的乘法跳过条件检查。哪个更有效/更快?不知道。一个好的编译器很可能会优化我假设的两个版本。
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 -O2 编译产生这个程序集:
.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:
如您所见,剩下的或f1
或所剩无几。f2
就 C++ 标准而言,允许编译器在优化方面做任何事情,只要它不改变可观察的行为(as if规则)。