2016-01-28 2 views
2

Существуют ли различия в скомпилированный код междуФункция возврата в ветвях `if` против вне` if`, в C++

double func(bool x) { 
    if (x) { 
    return 1.0; 
    } else { 
    return 2.0; 
    }; 
} 

и

double func(bool x){ 
    if (x) { 
    return 1.0; 
    }; 
    return 2.0; 
} 

Существуют причины производительности в пользу один над другим?

Единственное, что я знаю, это то, что второй быстрее набирать.


Я использовал g ++, но было бы интересно узнать, что происходит в других, если оно отличается.

+4

Чтобы улучшить читаемость, удалите ';' after '}'. – SergeyA

+2

Ну, вы можете скомпилировать его и посмотреть на сборку, чтобы узнать. – NathanOliver

+0

@NathanOliver Я не знаю, как это работает. Это легко? – myfirsttime1

ответ

4

Здесь нет различий в производительности, поскольку после того, как компилятор принимает ветвь «then», ветка «else» становится недоступной. Код, созданный оптимизирующим компилятором, должен быть идентичным.

Читаемость вашего примера также не изменяется. Однако, когда ветвь else очень длинная, а ветвь «затем» очень короткая, второй фрагмент читается лучше, потому что он имеет более низкий уровень вложенности.

Ситуация, когда ветка «then» короткая, и ветка «else» длинна, очень часто встречается - это происходит, когда вы выполняете проверку аргументов и генерируете исключение или предоставляете досрочное завершение в случае, если аргумент выходит за пределы диапазона. Преимущества второго подхода становятся еще более выраженными, когда вы рассматриваете множественные проверки в верхней части своей функции, например.

if (!arg1.isInRange()) { 
    return FAILURE_REASON_1; 
} else { 
    if (!arg2.isInRange()) { 
     return FAILURE_REASON_2; 
    } else { 
     if (!arg3.isInRange()) { 
      return FAILURE_REASON_3; 
     } else { 
      ... // Payload code goes here 
     } 
    } 
} 

vs.

if (!arg1.isInRange()) { 
    return FAILURE_REASON_1; 
} 
if (!arg2.isInRange()) { 
    return FAILURE_REASON_2; 
} 
if (!arg3.isInRange()) { 
    return FAILURE_REASON_3; 
} 
... // Payload code goes here 
+0

yep. Отступы - единственный фактор, который следует учитывать, и это важно. – bolov

+0

Еще одна вещь, которую следует учитывать, - если у вас много ветвей в ситуации if-else-if-else-if -else, поместив их в каждый блок, вы получите ошибку компилятора, если вы случайно забудете один путь. Если у вас есть полный возврат внизу, вы не получите эту ошибку. –

1

"Есть ли различия в скомпилированном коде между" является плохим началом в любом случае. Вывод сборки не указан стандартом C++, за исключением того, что он должен отражать правила, объявленные в стандарте. С одним миллионом или без него между каждой инструкцией - в большинстве случаев это одинаково соответствует. Поэтому, используя стандарт как ссылку, вы ничего не можете сказать о фактическом сборе, потому что он зависит от используемого фактического компилятора.
Для вопросов, касающихся, вам необходимо указать компилятор &, ОС, архитектуру и т. Д. В противном случае просто скомпилируйте и сравните сборку самостоятельно.

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


На моей машине x86-64 с GCC 5.2.0:

Первое:

0: 55      push %rbp 
    1: 48 89 e5    mov %rsp,%rbp 
    4: 89 f8     mov %edi,%eax 
    6: 88 45 fc    mov %al,-0x4(%rbp) 
    9: 80 7d fc 00    cmpb $0x0,-0x4(%rbp) 
    d: 74 0a     je  19 <_Z5func0b+0x19> 
    f: f2 0f 10 05 00 00 00 movsd 0x0(%rip),%xmm0 
    16: 00 
    17: eb 08     jmp 21 <_Z5func0b+0x21> 
    19: f2 0f 10 05 00 00 00 movsd 0x0(%rip),%xmm0 
    20: 00 
    21: 5d      pop %rbp 
    22: c3      retq 

Второе:

23: 55      push %rbp 
    24: 48 89 e5    mov %rsp,%rbp 
    27: 89 f8     mov %edi,%eax 
    29: 88 45 fc    mov %al,-0x4(%rbp) 
    2c: 80 7d fc 00    cmpb $0x0,-0x4(%rbp) 
    30: 74 0a     je  3c <_Z5func1b+0x19> 
    32: f2 0f 10 05 00 00 00 movsd 0x0(%rip),%xmm0 
    39: 00 
    3a: eb 08     jmp 44 <_Z5func1b+0x21> 
    3c: f2 0f 10 05 00 00 00 movsd 0x0(%rip),%xmm0 
    43: 00 
    44: 5d      pop %rbp 
    45: c3      retq 

Не отличаются.

+0

Странный ответ. Он предполагает, что нет причин писать эффективный код, поскольку компилятор «может включать в себя миллион нулей». – SergeyA

+0

@SergeyA Rewritten. Лучше? – Downvoter

1

Для начала нет необходимости включать пустое заявление

double func(bool x) { 
    if (x) { 
    return 1.0; 
    } else { 
    return 2.0; 
    }; 
    ^^^ 
} 

Что касается вопроса, то компилятор может генерировать один и тот же объектный код для обеих функций.

Но для меня, я предпочел бы следующую функцию :)

double func(bool x) { return x ? 1.0 : 2.0; } 

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

Кроме того, он сам может выполнять функции встроенного.

Таким образом, единственный вопрос, который может существовать относительно этих функций, - это тот, который более читабельен.

Что касается функций, которые вы показали, то более читаемые являются первыми по сравнению со вторым при условии, что в функциях нет других утверждений. Читая код второй функции, я бы потратил некоторое время, чтобы ответить на вопрос, почему не используется else. :)

Смежные вопросы