16

考虑以下:

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已知的情况下优化这个表达式,我应该更喜欢哪个版本?

4

4 回答 4

13

嗯,是的,两者都是等价的。bool是整数类型,true保证1在整数上下文中转换为,而false保证转换为0.

(反之亦然,即非零整数值保证true在布尔上下文中转换为,而零整数值保证false在布尔上下文中转换为。)

由于您使用的是无符号类型,因此可以轻松地提出其他可能基于 bit-hack 但完全可移植的同一事物的实现,例如

i & -(unsigned) b

尽管一个体面的编译器应该能够为您的任何版本自行选择最佳实现。

PS 虽然令我大吃一惊的是,GCC 4.1.2 实际上编译了所有三个变体,即它在基于乘法的变体中使用机器乘法指令。它足够聪明,可以cmovne在变体上使用指令?:使其无分支,这很可能使其成为最有效的实现。

于 2012-12-25T22:44:13.357 回答
6

是的。可以安全地假设trueis1falseis0像你一样在表达式中使用并且得到保证:

C++11,整体促销,4.5

bool 类型的右值可以转换为 int 类型的右值,false 变为 0,true 变为 1。

于 2012-12-25T22:48:35.643 回答
1

编译器将使用隐式转换来生成unsigned intfrom b,所以,是的,这应该可以工作。您通过简单的乘法跳过条件检查。哪个更有效/更快?不知道。一个好的编译器很可能会优化我假设的两个版本。

于 2012-12-25T22:40:56.300 回答
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++ 标准而言,允许编译器在优化方面做任何事情,只要它不改变可观察的行为(as if规则)。

于 2012-12-25T23:27:58.790 回答