请考虑以下事项:
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
时优化此表达式,我更喜欢哪个版本?
答案 0 :(得分:11)
嗯,是的,两者都是等价的。 bool
是一个整数类型,true
保证在整数上下文中转换为1
,而false
保证转换为0
。
(反过来也是如此,即保证非零整数值在布尔上下文中转换为true
,而保证零整数值在布尔上下文中转换为false
。)< / p>
由于您正在使用无符号类型,因此可以轻松地提出其他的,可能是基于位的,但是完全可移植的同类内容的实现,例如
i & -(unsigned) b
虽然一个不错的编译器应该能够为你的任何版本选择最好的实现。
P.S。虽然令我惊讶的是,GCC 4.1.2几乎字面上编译了所有三个变体,即它在基于乘法的变体中使用了机器乘法指令。它足够聪明,可以在cmovne
变体上使用?:
指令使其无分支,这很可能使其成为最有效的实现。
答案 1 :(得分:6)
是。假设true
1
false
和0
{{1}}在表达式中使用时可以安全地保证:
C ++ 11,积分促销,4.5 :
bool类型的rvalue可以转换为int类型的rvalue 假成为零,真正成为一个。
答案 2 :(得分:1)
编译器将使用隐式转换从unsigned int
生成b
,所以,是的,这应该有效。你正在通过简单的乘法跳过条件检查。哪一个更有效/更快?不知道。一个好的编译器很可能会优化我认为的两个版本。
答案 3 :(得分: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 -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 ++标准而言,允许编译器对优化做任何事情,只要它不改变可观察行为(就好像规则)。