Булево умножение в с ++?

Учтите следующее:

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 известны во время компиляции, какую версию мне выбрать?

13

Решение

Ну да, оба эквивалентны. bool является интегральным типом и true гарантированно конвертировать в 1 в целочисленном контексте, в то время как false гарантированно конвертировать в 0,

(Обратное также верно, то есть ненулевые целочисленные значения гарантированно преобразуются в true в логическом контексте, в то время как нулевые целые значения гарантированно преобразуются в false в логическом контексте.)

Поскольку вы работаете с неподписанными типами, можно легко придумать другие, возможно, основанные на битах, но совершенно портативные реализации того же самого, например

i & -(unsigned) b

хотя достойный компилятор должен иметь возможность выбрать лучшую реализацию для любой из ваших версий.

Постскриптум К моему большому удивлению, GCC 4.1.2 скомпилировал все три варианта буквально буквально, то есть он использовал инструкцию машинного умножения в варианте на основе умножения. Это было достаточно умно, чтобы использовать cmovne инструкция по ?: вариант, чтобы сделать его без ветвления, что вполне возможно сделало его наиболее эффективной реализацией.

11

Другие решения

Да. Можно предположить true является 1 а также false является 0 при использовании в выражениях, как вы и гарантировано:

C ++ 11, Integral Promotions, 4.5:

Значение типа bool можно преобразовать в значение типа int с помощью
ложь становится нулем, а правда становится единым.

6

Компилятор будет использовать неявное преобразование, чтобы сделать unsigned int от bТак что да, это должно работать. Вы пропускаете проверку условий простым умножением. Какой из них более эффективен / быстрее? Не знаю Хороший компилятор, скорее всего, оптимизировал бы обе версии.

1

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 ++, то компилятору разрешено делать все, что касается оптимизации, если он не меняет наблюдаемого поведения ( как будто правило).

0
По вопросам рекламы [email protected]