Почему n ++ выполняется быстрее, чем n = n + 1? - PullRequest
31 голосов
/ 21 мая 2010

На языке C, почему n++ выполняется быстрее, чем n=n+1?

(int n=...;  n++;)
(int n=...;  n=n+1;)

Наш инструктор задал этот вопрос на сегодняшнем занятии. (это не домашняя работа)

Ответы [ 10 ]

102 голосов
/ 21 мая 2010

Это было бы верно, если вы работаете над "каменным веком" компилятором ...

В случае "каменный век" :
++n быстрее n++ быстрее n=n+1
Машина обычно имеет increment x, а также add const to x

  • В случае n++ у вас будет только 2 доступа к памяти (чтение n, inc n, запись n)
  • В случае n=n+1 у вас будет 3 доступа к памяти (чтение n, чтение const, добавление n и const, запись n)

Но сегодняшний компилятор автоматически преобразует n=n+1 в ++n, и он сделает больше, чем вы можете себе представить! *

Также на современных процессорах, вышедших из строя - несмотря на случай "каменного века" компилятора - время работы может вообще не быть затронуто во многих случаях !!

Относящиеся

42 голосов
/ 21 мая 2010

В GCC 4.4.3 для x86, с или без оптимизаций, они компилируются с точно таким же кодом сборки и, следовательно, занимают столько же времени для выполнения.Как вы можете видеть в сборке, GCC просто конвертирует n++ в n=n+1, а затем оптимизирует его в дополнение к одной инструкции (в -O2).

Предложение вашего инструктора, что n++ быстрееприменимо только к очень старым неоптимизирующим компиляторам, которые не были достаточно умны, чтобы выбрать инструкции по обновлению на месте для n = n + 1.Эти компиляторы устарели в мире ПК в течение многих лет, но все еще могут быть найдены для странных проприетарных встроенных платформ.

C код:

int n;

void nplusplus() {
    n++;
}

void nplusone() {
    n = n + 1;
}

Выходная сборка (без оптимизации):

    .file   "test.c"
    .comm   n,4,4
    .text
.globl nplusplus
    .type   nplusplus, @function
nplusplus:
    pushl   %ebp
    movl    %esp, %ebp
    movl    n, %eax
    addl    $1, %eax
    movl    %eax, n
    popl    %ebp
    ret
    .size   nplusplus, .-nplusplus
.globl nplusone
    .type   nplusone, @function
nplusone:
    pushl   %ebp
    movl    %esp, %ebp
    movl    n, %eax
    addl    $1, %eax
    movl    %eax, n
    popl    %ebp
    ret
    .size   nplusone, .-nplusone
    .ident  "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
    .section    .note.GNU-stack,"",@progbits

Выходная сборка (с оптимизацией -O2):

    .file   "test.c"
    .text
    .p2align 4,,15
.globl nplusplus
    .type   nplusplus, @function
nplusplus:
    pushl   %ebp
    movl    %esp, %ebp
    addl    $1, n
    popl    %ebp
    ret
    .size   nplusplus, .-nplusplus
    .p2align 4,,15
.globl nplusone
    .type   nplusone, @function
nplusone:
    pushl   %ebp
    movl    %esp, %ebp
    addl    $1, n
    popl    %ebp
    ret
    .size   nplusone, .-nplusone
    .comm   n,4,4
    .ident  "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
    .section    .note.GNU-stack,"",@progbits
14 голосов
/ 21 мая 2010

Компилятор оптимизирует n + 1 в ничто.

Вы имеете в виду <b>n =</b> n + 1?

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

5 голосов
/ 21 мая 2010

Кто говорит, что это делает?Ваш компилятор все это оптимизирует, что делает его спорным.

3 голосов
/ 21 мая 2010

Современные компиляторы должны иметь возможность распознавать обе формы как эквивалентные и преобразовывать их в формат, который лучше всего работает на вашей целевой платформе. Из этого правила есть одно исключение: доступ к переменным, который имеет побочные эффекты. Например, если n - это какой-то аппаратный регистр с отображением в памяти, чтение из него и запись в него может сделать больше, чем просто передать значение данных (например, чтение может очистить прерывание). Вы должны использовать ключевое слово volatile, чтобы сообщить компилятору, что он должен быть осторожен при оптимизации доступа к n, и в этом случае компилятор может сгенерировать другой код из n++ (операция приращения) и n = n + 1 ( операции чтения, добавления и сохранения). Однако для обычных переменных компилятор должен оптимизировать обе формы для одного и того же.

2 голосов
/ 21 мая 2010

На языке C побочный эффект выражений n++ равен по определению , что эквивалентно побочному эффекту выражения n = n + 1. Поскольку ваш код основан только на побочных эффектах, сразу очевидно, что правильный ответ заключается в том, что эти выражения всегда имеют точно эквивалентную производительность. (Независимо от каких-либо настроек оптимизации в компиляторе, кстати, поскольку проблема не имеет абсолютно никакого отношения к каким-либо оптимизациям.)

Любое практическое расхождение в производительности этих выражений возможно только в том случае, если компилятор намеренно (и злонамеренно!) Пытается ввести это расхождение. Но в этом случае, конечно, все может пойти по-другому, т. Е. В зависимости от того, каким образом автор компилятора захотел исказить его.

2 голосов
/ 21 мая 2010

На самом деле причина в том, что оператор определяется после исправления иначе, чем для предварительного исправления. ++n будет увеличивать «n» и возвращать ссылку на «n», в то время как n++ будет увеличивать «n», возвращая const копию «n». Следовательно, фраза n = n + 1 будет более эффективной. Но я должен согласиться с вышеуказанными постерами. Хорошие компиляторы должны оптимизировать неиспользуемый возвращаемый объект.

2 голосов
/ 21 мая 2010

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

1 голос
/ 24 декабря 2010

Я думаю, что это скорее аппаратный вопрос, нежели программный ... Если я точно помню, в старых процессорах n = n + 1 требует двух мест памяти, где ++ n - просто команда микроконтроллера Но я сомневаюсь, что это относится к современной архитектуре ...

0 голосов
/ 24 декабря 2010

Все это зависит от директив компилятора / процессора / компиляции. Поэтому делать какие-либо предположения о том, «что вообще быстрее» - не очень хорошая идея.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...