Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: i++ против ++i
Форум на CrossPlatform.RU > Курилка > Трёп
Red Devil
Я согласен с автором в том, что опен соурс программисты слишком непрофиссионально относятся к работе. В большенстве своем пишут на Си, те кто пишут на С++ используют его неправильно.
Стоит хотя бы исходные коды посмотреть, ужас, ужас. Естественно все будет тормозить, когда циклы не оптимизируется, пишется i++, вместо ++i, функция вызыова размерности вызывается каждый при проходе цикла, вместо того чтобы ее сохранить при начале проходе и сравнивать значение. Лишние переменные с неопределенными сроком жизни, отсуствие применения паттернов проектирования - это я его могу продолжать еще долго. Привычка пихать все в классы, ничего не разделяя. На первый взгляд кажется что типа это дело автора опен соурс, но это напрямую влияет на архитуктуру проекта и того кто будет в дальшнейшем его развивать. Большенство проектов умирают, потому что никто не хочет поддерживать тот убогий код, который был заложен автором при разработке, в том числе и сам автор.
Статью читал где-то месяц назад, про программистов во всем согласен, что там написано.
Litkevich Yuriy
Цитата(Red Devil @ 20.7.2008, 15:27) *
пишется i++, вместо ++i

я не знаток Си, но думаю во вменяемом компиляторе результат должен быть одинаковым.
А насчет професиональности OSS-програмеров согласен. У профана скорее всего времени не будет чем-то заниматься, конечно бывают исключения.
Например история про TortoiseSVN писали его несколько чуваков, пока не появился один и сказал, "блин, вас кто так софт писать научил" иначал все переделывать, теперь мы имеем, возможно, лучший SVN клиент под виндовоз, я ему как-то писал, чтобы он сделал и под линух, но он сказал, что нету времени тщательно изучать Линух, а не тщательно он делать не будет.
Red Devil
Цитата(Litkevich Yuriy @ 20.7.2008, 16:53) *
я не знаток Си, но думаю во вменяемом компиляторе результат должен быть одинаковым.

нет, результат одинаковым не будет. Об этом уже многое говорилось и писалось в книгах таких авторов как Мейрс, Саттер, Джосьюттис.
Litkevich Yuriy
по опыту написания программ на ассемблере для контроллеров, а рание и для проца типа Z80, могу утверждать, что результат можно сделать по размеру кода и времени выполнения одинаковым, хотя интеловский проц редкостное говно, но я думаю и там это осуществимо. Просто у некоторых людей ума слихком много вот у них и получается как у класиков "Горе от ума"
void*
Цитата(Litkevich Yuriy @ 20.7.2008, 15:53) *
я не знаток Си, но думаю во вменяемом компиляторе результат должен быть одинаковым

разница есть, и довольно существенная, т.к. при использовании i++ расходуется памяти на sizeof(i) байт больше, т.к. создается временная копия объекта. Ниже два фрагмента кода, иллюстрирующие различия этих операторов(что происходит при их использовании):

++i
{
return i += 1;
}


i++
{ 
int temp = i; //создается временный объект, т.е. увеличивается расход памяти. P.S. тип int я взял только для примера, может  быть и другой тип
i += 1;
return temp; // (!) возвращается временный объект
}
Red Devil
Помимо этого в первом случае возращается ссылка, а во втором значение. Для простых типов между ссылкой и значением разницы еще не будет, а вот для итераторов - очень большая разница.
AD
Цитата
Помимо этого в первом случае возращается ссылка, а во втором значение. Для простых типов между ссылкой и значением разницы еще не будет, а вот для итераторов - очень большая разница.

Для целочисленного типа и простых итераторах для современных компиляторов разницы не будет, насколько я знаю от программистов, которые делают встроенное ПО для авиации! :) Я еще только учусь на такого программиста, но встроенное ПО пока что не доверяют.
Litkevich Yuriy
я говорил о вменяемом компиляторе, но не бесплатном, в IAR разницы ни какой, я давно про эту особенность Си прочитал, и смотрел результат работы разных компиллеров. в HiTech и IAR нет разницы, просто люди умеют писать оптимизирующие копиллеры. А GNU это бесплатный компиллер, с минимально возможной оптимизацией, как там прочие поживают не в курсе.

void*, пример неудачный т.к. он не объясняет причины копирования, выглядит не логично.
Надо с какой-нибудь допоперацией, например:
if (++i > k)
   goto 1branch
else
   goto 2branch


if (i++ > k)
   goto 1branch
else
   goto 2branch
Багира
Вот вас понесло... :mocking:
Litkevich Yuriy
для первого варианта псевдо ассемблер так выглядит:
1.            inc i;
2.            comp i,k;  //если i>k, то пропускаем следующую команду
3.            goto 1branch;
4.            foo; //2-ая ветка
...
n. 1branch    foo; [i]1-ая ветка[/i]


для второго варианта псевдо ассемблер так выглядит:
1.            comp i,k;  //если i>k, то пропускаем следующую команду
2.            goto 1branch;
3.            inc i;  //2-ая ветка
...
n. 1branch    inc i; //1-ая ветка


и того один инкремент лишний. Если инкремент должен быть сложного типа данных вместо inc i вызывается функция.
Red Devil
Цитата
if (++i > k)
goto 1branch
else
goto 2branch
Language: cpp


if (i++ > k)
goto 1branch
else
goto 2branch

Этот пример не удачный, т.к. тут выполняются разные по семантике задачи.


Цитата(Litkevich Yuriy @ 21.7.2008, 11:43) *
я говорил о вменяемом компиляторе, но не бесплатном, в IAR разницы ни какой, я давно про эту особенность Си прочитал, и смотрел результат работы разных компиллеров. в HiTech и IAR нет разницы, просто люди умеют писать оптимизирующие копиллеры. А GNU это бесплатный компиллер, с минимально возможной оптимизацией, как там прочие поживают не в курсе.

Так я про это и говорю, что для GNU компилеров делается и это нужно учитывать.

Цитата(AD @ 21.7.2008, 11:01) *
Для целочисленного типа и простых итераторах для современных компиляторов разницы не будет, насколько я знаю от программистов, которые делают встроенное ПО для авиации! Я еще только учусь на такого программиста, но встроенное ПО пока что не доверяют.

Для итераторов есть и очень существенная, при случае скажи об этом вашем программистам и еще книги посоветуй им почитать про стандартную библиотеку, раз таких основ не знают. Могут так же посмотреть исходные коды STL и подумать, почему там написано так и именно так, и никак иначе.
Вот пример, как генерируется код для типов, у которых определены собственные инкрементные операторы ++ (и для итераторов тоже, вне зависимости от компилятора).
Вот такой код генерируются для ++a; (69 строк)
    .file    "main.cpp"
    .text
    .align 2
.globl main
    .type    main, @function
main:
.LFB8:
    pushl    %ebp
.LCFI0:
    movl    %esp, %ebp
.LCFI1:
    subl    $8, %esp
.LCFI2:
    andl    $-16, %esp
    movl    $0, %eax
    subl    %eax, %esp
    subl    $8, %esp
    pushl    $0
    leal    -4(%ebp), %eax
    pushl    %eax
.LCFI3:
    call    _ZN1AC1Ei
    addl    $16, %esp
    subl    $12, %esp
    leal    -4(%ebp), %eax
    pushl    %eax
    call    _ZN1AppEv
    addl    $16, %esp
    movl    $0, %eax
    leave
    ret
.LFE8:
    .size    main, .-main
    .section    .gnu.linkonce.t._ZN1AC1Ei,"ax",@progbits
    .align 2
    .weak    _ZN1AC1Ei
    .type    _ZN1AC1Ei, @function
_ZN1AC1Ei:
.LFB9:
    pushl    %ebp
.LCFI4:
    movl    %esp, %ebp
.LCFI5:
    movl    8(%ebp), %edx
    movl    12(%ebp), %eax
    movl    %eax, (%edx)
    popl    %ebp
    ret
.LFE9:
    .size    _ZN1AC1Ei, .-_ZN1AC1Ei
    .section    .gnu.linkonce.t._ZN1AppEv,"ax",@progbits
    .align 2
    .weak    _ZN1AppEv
    .type    _ZN1AppEv, @function
_ZN1AppEv:
.LFB10:
    pushl    %ebp
.LCFI6:
    movl    %esp, %ebp
.LCFI7:
    movl    8(%ebp), %eax
    incl    (%eax)
    movl    8(%ebp), %eax
    popl    %ebp
    ret
.LFE10:
    .size    _ZN1AppEv, .-_ZN1AppEv
    .section    .note.GNU-stack,"",@progbits
    .ident    "GCC: (GNU) 3.3.4"


А вот такой код для a++ (101 строка)
    .file    "main.cpp"
    .text
    .align 2
.globl main
    .type    main, @function
main:
.LFB8:
    pushl    %ebp
.LCFI0:
    movl    %esp, %ebp
.LCFI1:
    subl    $8, %esp
.LCFI2:
    andl    $-16, %esp
    movl    $0, %eax
    subl    %eax, %esp
    subl    $8, %esp
    pushl    $0
    leal    -4(%ebp), %eax
    pushl    %eax
.LCFI3:
    call    _ZN1AC1Ei
    addl    $16, %esp
    leal    -8(%ebp), %edx
    subl    $4, %esp
    pushl    $0
    leal    -4(%ebp), %eax
    pushl    %eax
    pushl    %edx
    call    _ZN1AppEi
    addl    $12, %esp
    movl    $0, %eax
    leave
    ret
.LFE8:
    .size    main, .-main
    .section    .gnu.linkonce.t._ZN1AC1Ei,"ax",@progbits
    .align 2
    .weak    _ZN1AC1Ei
    .type    _ZN1AC1Ei, @function
_ZN1AC1Ei:
.LFB9:
    pushl    %ebp
.LCFI4:
    movl    %esp, %ebp
.LCFI5:
    movl    8(%ebp), %edx
    movl    12(%ebp), %eax
    movl    %eax, (%edx)
    popl    %ebp
    ret
.LFE9:
    .size    _ZN1AC1Ei, .-_ZN1AC1Ei
    .section    .gnu.linkonce.t._ZN1AppEi,"ax",@progbits
    .align 2
    .weak    _ZN1AppEi
    .type    _ZN1AppEi, @function
_ZN1AppEi:
.LFB10:
    pushl    %ebp
.LCFI6:
    movl    %esp, %ebp
.LCFI7:
    pushl    %ebx
.LCFI8:
    subl    $4, %esp
.LCFI9:
    movl    8(%ebp), %ebx
    movl    12(%ebp), %eax
    movl    (%eax), %eax
    movl    %eax, (%ebx)
    subl    $12, %esp
    pushl    12(%ebp)
.LCFI10:
    call    _ZN1AppEv
    addl    $16, %esp
    movl    %ebx, %eax
    movl    -4(%ebp), %ebx
    leave
    ret    $4
.LFE10:
    .size    _ZN1AppEi, .-_ZN1AppEi
    .section    .gnu.linkonce.t._ZN1AppEv,"ax",@progbits
    .align 2
    .weak    _ZN1AppEv
    .type    _ZN1AppEv, @function
_ZN1AppEv:
.LFB11:
    pushl    %ebp
.LCFI11:
    movl    %esp, %ebp
.LCFI12:
    movl    8(%ebp), %eax
    incl    (%eax)
    movl    8(%ebp), %eax
    popl    %ebp
    ret
.LFE11:
    .size    _ZN1AppEv, .-_ZN1AppEv
    .section    .note.GNU-stack,"",@progbits
    .ident    "GCC: (GNU) 3.3.4"


Вот код на С++, который тестировался :
class A
{
public:
    A(int val) : m_val(val) {}
    A & operator ++ ()    
    {
    ++m_val;
    return *this;
    }
    
    A operator ++(int)
    {
    A temp(*this);
    ++*this;
    return temp;
    }
    
    int m_val;
};

int main()
{
    A a(0);
    
    a++;
    //++a;
    
    return 0;
}
AD
Цитата
Для итераторов есть и очень существенная, при случае скажи об этом вашем программистам и еще книги посоветуй им почитать про стандартную библиотеку, раз таких основ не знают. Могут так же посмотреть исходные коды STL и подумать, почему там написано так и именно так, и никак иначе.

Приколист, однако! :) Вообще-то они и проверяли. STL во встроенном ПО не используется в целях надежности. Для современных компиляторов эта разница по барабану. А стандартные итераторы, как я их понял, это далеко не те, что в stl!
void*
Цитата(AD @ 21.7.2008, 18:14) *
STL во встроенном ПО не используется в целях надежности.

прикольно однако. Ты считаешь STL ненадежной? :)
Цитата(AD @ 21.7.2008, 18:14) *
А стандартные итераторы, как я их понял, это далеко не те, что в stl!

еще прикольней :) и чем же они так сильно отличаются?
AD
Цитата(void* @ 21.7.2008, 19:43) *
прикольно однако. Ты считаешь STL ненадежной? :)
Цитата(AD @ 21.7.2008, 18:14) *
А стандартные итераторы, как я их понял, это далеко не те, что в stl!

еще прикольней :) и чем же они так сильно отличаются?

На 1 вопрос ответ: не я так считаю, а таково требование к встроенному софту - stl не использовать!
На 2 вопрос: я точно ответить не смогу. Я знаю, что в stl используют динамическую память, что как-раз и не нравится, и чего и боятся при использовании во встроенном софте. Самолет или вертолет не должен в пути отказать! :)
Litkevich Yuriy
во встроенном ПО стандартных библиотек избегают по причине того что редкий Си компиллер будет компилить только те функции которые нужны, он сунет в бинарь все без разбора.

тотже принтф съедает около 1.5кило памяти программ, сильно накладно. а стандартные итераторы в С++ помоему это как раз и есть STL.
AD
Цитата(Litkevich Yuriy @ 21.7.2008, 20:42) *
во встроенном ПО стандартных библиотек избегают по причине того что редкий Си компиллер будет компилить только те функции которые нужны, он сунет в бинарь все без разбора.

Из-за этого тоже. Но первопричина - как раз динамическая память! Ее боятся, а в stl она повсюду используется! ;)
Litkevich Yuriy
Цитата(AD @ 21.7.2008, 23:44) *
Ее боятся

Просто скушает много во время работы, в этом-то и касяк, когда руками выделяешь ты всегда видишь сколько.
Я масив выделял, а потом по его адресу размещал динамические переменные, при крайней нужде.
Novak
Цитата(Red Devil @ 21.7.2008, 17:54) *
Этот пример не удачный, т.к. тут выполняются разные по семантике задачи.

Эээ.. Ну, а при равных по семантике задачах, например
for (int i=0; ...; i++)
for (int i=0; ...; ++i)

Нормальный компилятор и не должен в итоге делать различий между инкрементной и декрементной формами.
void*
Цитата(Novak @ 22.7.2008, 5:25) *
Нормальный компилятор и не должен в итоге делать различий между инкрементной и декрементной формами.

а для чего тогда по-твоему вообще создавали две формы этого оператора? чтобы компилятор не делал между ними различий? есть ситуации, в которых предпочтительнее одна форма, есть в которых предпочтительнее другая, но они не должны быть одинаково восприняты компилятором, иначе исчезает весь их смысл
Red Devil
Цитата(Novak @ 22.7.2008, 5:25) *
Нормальный компилятор и не должен в итоге делать различий между инкрементной и декрементной формами.

Согласен, для простых типов современные компиляторы нормально отработают.
Когда же операторы ++ определены программистом (а это обычно итераторы) - компилятор не знает разницы, может программист по своему реализовал оператор ++ и у них асболютно разная логика, поэтому он ничего не будет оптимизировать.
Поэтому писать ++i нужно вводить в привычку, и это является хорошем тоном/стилем в программировании на С++.
Мне во всяком случае достаточно посмотреть как реализован цикл for, чтобы определить базовые навыки программиста.
Andrew Selivanov
Рискуя нарваться на крики негодования, но все же:
Инженерный подход: так, оно должно нормально работать по алгоритму M, доделаю, нужно будет еще модули X, Y, Z
Программистский подход: как же мне написать, ++i или i++? как будет быстрее?.. я выиграю 0,01мс/3 байта или нет? (спустя три часа) дада, да, я понял, ++i гораздо лучше, i++ нужно нахрен убрать из языка!
8)
Litkevich Yuriy
:)
AD
Andrew Selivanov, логично! :)
Tonal
Не совсем так. Для твоего примера, нормальный современный компилятор, сообразит, что возвращаемое значение не используется - значит его можно выкинуть. Естественно, это в случае, когда включена хоть какая-то оптимизация.
struct A {
  A() : m_val(0) {}
  A(int val) : m_val(val) {}
  A & operator ++ () {
    ++m_val;
    return *this;
  }
  
  A operator ++(int) {
    A temp(*this);
    ++*this;
    return temp;
  }
  bool operator ==(const A& x) {
    return m_val == x.m_val;
  }
  bool operator !=(const A& x) {
    return m_val != x.m_val;
  }

  private:  
    int m_val;
};

int f1(A cur, const A& end) {
  int r = 0;
  for (; cur != end; ++cur)
    ++r;
  return r;
}

int f2(A cur, const A& end) {
  int r = 0;
  for (; cur != end; cur++)
    ++r;
  return r;
}

g++ (GCC) 3.4.5 (mingw-vista special r3)
>g++ -S -O1 iter.cpp
    .file    "iter.cpp"
    .text
    .align 2
.globl __Z2f11ARKS_
    .def    __Z2f11ARKS_;    .scl    2;    .type    32;    .endef
__Z2f11ARKS_:
    pushl    %ebp
    movl    %esp, %ebp
    pushl    %ebx
    movl    12(%ebp), %ebx
    movl    $0, %ecx
    movl    8(%ebp), %eax
    movl    %eax, %edx
    cmpl    (%ebx), %eax
    je    L9
L7:
    incl    %ecx
    leal    1(%edx), %eax
    movl    %eax, %edx
    cmpl    (%ebx), %eax
    jne    L7
    movl    %eax, 8(%ebp)
L9:
    movl    %ecx, %eax
    popl    %ebx
    popl    %ebp
    ret
    .align 2
.globl __Z2f21ARKS_
    .def    __Z2f21ARKS_;    .scl    2;    .type    32;    .endef
__Z2f21ARKS_:
    pushl    %ebp
    movl    %esp, %ebp
    pushl    %ebx
    movl    12(%ebp), %ebx
    movl    $0, %ecx
    movl    8(%ebp), %eax
    movl    %eax, %edx
    cmpl    (%ebx), %eax
    je    L20
L18:
    incl    %ecx
    leal    1(%edx), %eax
    movl    %eax, %edx
    cmpl    (%ebx), %eax
    jne    L18
    movl    %eax, 8(%ebp)
L20:
    movl    %ecx, %eax
    popl    %ebx
    popl    %ebp
    ret

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

Твоё рассуждение верно или когда оптимизация отрублена напрочь, или когда конструктор, деструктор или сами операторы имеют побочные эффекты (например отладочную печать, или подсчёт ресурсов) - тогда компилятору деваться некуда, и придётся оставлять всё как написано. :)
Red Devil
Цитата(Andrew Selivanov @ 22.7.2008, 16:09) *
Рискуя нарваться на крики негодования, но все же:
Инженерный подход: так, оно должно нормально работать по алгоритму M, доделаю, нужно будет еще модули X, Y, Z
Программистский подход: как же мне написать, ++i или i++? как будет быстрее?.. я выиграю 0,01мс/3 байта или нет? (спустя три часа) дада, да, я понял, ++i гораздо лучше, i++ нужно нахрен убрать из языка!

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

Цитата(AD @ 22.7.2008, 16:25) *
Не совсем так. Для твоего примера, нормальный современный компилятор, сообразит, что возвращаемое значение не используется - значит его можно выкинуть. Естественно, это в случае, когда включена хоть какая-то оптимизация.

Цитата(Red Devil @ 22.7.2008, 14:56) *
Когда же операторы ++ определены программистом (а это обычно итераторы) - компилятор не знает разницы, может программист по своему реализовал оператор ++ и у них асболютно разная логика, поэтому он ничего не может оптимизировать.

И дело тут не в том, что используется возращаемое значение или нет, потому что даже если оно не используется, оно все равно будет возращено и код для него отработает.
ЙаМайскЫйПчОЛ
Посвящается вечному спору)
Инкремент постфиксный(i++) и (++i)префиксный нужны языку программирования такому как С++, ибо он не ++С )))
Это две функции которые выполняют, одно и тоже только в разное время, гибкость которая появляется в языке с введением двух, казалось бы одинаковых функций, но работающих слегка различно, постоянно приводит к спору о неоднозначности интерпретированния таких записей и как следствие к различным реализациям в алгоритмах компиляторов на соответствующие постфиксные и префиксные операции.

Значение ++x будет новое(увеличенное) значение x, т.е y=++x => y=(x+=1). Напротив, значением x++ является старое значение x, т.е. y=x++ => y=(t=x,x+=1,t) тип t такойже как и x.

по поводу
Цитата(Red Devil @ 23.7.2008, 8:34) *
Это отличиает программиста от не программиста.
И если ты не знаешь таких базовых понятий, что любая операция в цикле дорогостоящая - говорить вообще не о чем. Программист вообще от думать не должен, в цикле всегда должен быть оператор ++i.


Страуструп в одном из примеров:

int length = strlen(q);
for(int i=0; i<=length; i++) p[i]=q[i]

))))
и циклы while с указателями реализует также.
Я тут полистал => Он вообще в операции циклов отдает предпочтение постфиксной записи.

Не путайте реализацию-интерпретации-понимания-функциональности-операции конкретным кодером в конкретном компилере и изначальную идею потенциального-увеличения-однозначности-визуальной-интерпретации-операции-и-локаничности-записи.

Цитата(AD @ 21.7.2008, 12:01) *
Для целочисленного типа и простых итераторах для современных компиляторов разницы не будет, насколько я знаю от программистов, которые делают встроенное ПО для авиации! smile.gif Я еще только учусь на такого программиста, но встроенное ПО пока что не доверяют.


Надо отличать ОСРВ(ОС Реального времени, типа QNX), от OC, правило звучит так: Если кодишь под ОСРВ - кодь на Си и в статике, если кодишь под ОС, пользуй блага С++ )
AD
Цитата(ЙаМайскЫйПчОЛ @ 23.7.2008, 10:16) *
Не путайте реализацию-интерпретации-понимания-функциональности-операции конкретным кодером в конкретном компилере и изначальную идею потенциального-увеличения-однозначности-визуальной-интерпретации-операции-и-локаничности-записи.

:blink:
А можно по-русски или по рабоче-крестьянски? :)
Цитата
Надо отличать ОСРВ(ОС Реального времени, типа QNX), от OC, правило звучит так: Если кодишь под ОСРВ - кодь на Си и в статике, если кодишь под ОС, пользуй блага С++ )

Про статику согласен абсолютно. А вот на счет С/С++: для того, чтобы код был более понятен и структурирован, а также для множества других удобств, которые предоставляет С++, мы используем С++ именно для приложений на бортовых приборах. Предельные участки и код, который работает жестко от железа, естественно, пишется на С. :)
ЙаМайскЫйПчОЛ
Цитата(AD @ 23.7.2008, 10:39) *
Про статику согласен абсолютно. А вот на счет С/С++: для того, чтобы код был более понятен и структурирован, а также для множества других удобств, которые предоставляет С++, мы используем С++ именно для приложений на бортовых приборах. Предельные участки и код, который работает жестко от железа, естественно, пишется на С. smile.gif


С++ в статике, без ООП, мне кажется, это и есть Си. Но не мне судить о преимуществах.

Цитата(ЙаМайскЫйПчОЛ @ 23.7.2008, 10:16) *
Не путайте реализацию-интерпретации-понимания-функциональности-операции конкретным кодером в конкретном компилере и изначальную идею потенциального-увеличения-однозначности-визуальной-интерпретации-операции-и-локаничности-записи.


разделение операции на постфиксную и префиксную должны были сделать код более наглядным и локаничным, подразумевая под собой возможность компилятора оптимизировать инкремент в том числе с помощью битового сдвига, и изначально предпологались не больше не меньше, а как механизм увеличения на 1 у.е. (это мое мнение) но с разными возвращаемыми значениями. При проектировании учитывалась возможность перегрузки операторов, а так как инкремент тоже оператор => перегрузили и его, что привело к удобной и оптимизированной работе с указателями и как следствие итераторами.
Но частично, оптимизация в реализации и функциональность была не использована при создании компиляторов из-за многих неоднозначностей возникающих при использовании этих операций. Сколько компиляторов, столько и алгоритмов оптимизации кода.
AD
Цитата(ЙаМайскЫйПчОЛ @ 23.7.2008, 10:59) *
С++ в статике, без ООП, мне кажется, это и есть Си. Но не мне судить о преимуществах.

ну... что-то переборщили

Где есть и возможность (а иногда и необходимость), там используются и наследование, и полиморфизм, и инкапсуляция. Ладно, в общем-то уяснили все! ;) :)

А за разъяснение спасибо!
Tonal
Цитата(Red Devil @ 23.7.2008, 11:34) *
Цитата
Не совсем так. Для твоего примера, нормальный современный компилятор, сообразит, что возвращаемое значение не используется - значит его можно выкинуть. Естественно, это в случае, когда включена хоть какая-то оптимизация.

Цитата(Red Devil @ 22.7.2008, 14:56) *
Когда же операторы ++ определены программистом (а это обычно итераторы) - компилятор не знает разницы, может программист по своему реализовал оператор ++ и у них асболютно разная логика, поэтому он ничего не может оптимизировать.

И дело тут не в том, что используется возращаемое значение или нет, потому что даже если оно не используется, оно все равно будет возращено и код для него отработает.

Я же привёл плюсовый код с совмещением (перегрузкой) инкремента, и асмовый листинг.
Покажи, пожалуйста, код, в функции f2 (в асме __Z2f21ARKS_), который отвечает за создание неиспользуемого экземпляра и его возврат.
Его нет.
Дело в том, что если у действия нет побочных эффектов, и его результат нигде не используется, его можно смело выкидывать из программы. Именно это и делает оптимизатор. Причём там всё ещё несколько сложнее, т.к. оптимизатор работает не с языковыми конструкциями, не с деревом разбора, а работает он с промежуточным объектным кодом, на уровне которого уже никакого С++ или там Ada нет - есть инструкции некоторой универсальной машины, которые потом, после оптимизации, преобразуются в объектный код.
Почитай например "Красного дракона" (Ахо А., Сети Р., Ульман Дж. Компиляторы. Принципы, технологии, инструменты)
Там всё это подробно изложено. :)

Это не агитация за то, чтобы убрать постинкремет из языка.
Я довольно хорошо понимаю разницу между этими операторами, и сам всегда пишу for (...; ++i).
Просто не нужно создавать мифы и догмы, нужно аккуратно пользоваться доступным инструментарием. :)
Litkevich Yuriy
Цитата(ЙаМайскЫйПчОЛ @ 23.7.2008, 13:16) *
Значение ++x будет новое(увеличенное) значение x, т.е y=++x => y=(x+=1). Напротив, значением x++ является старое значение x, т.е. y=x++ => y=(t=x,x+=1,t) тип t такойже как и x


так до меня и не доходит, зачем стронники разного эфекта насильно суют доппеременную, мнеб такая ересь даже в голову не пришла,
и то, и то разделится на две операции, вот так:
y=++x => x+=1, y=x
y=x++ => y=x, x+=1
где тут кривые гвозди?
ЙаМайскЫйПчОЛ
кстати, забыл сказать, что использование цикла for, на мой взгляд, является признаком плохого стиля программирования.
Потому что:
если логику использования цикла for нельзя выразить через while и do while, то это является свидетельством плохо организованного алгоритма или неверной логики. :rolleyes:

Цитата(Litkevich Yuriy @ 23.7.2008, 13:06) *
так до меня и не доходит, зачем стронники разного эфекта насильно суют доппеременную, мнеб такая ересь даже в голову не пришла,
и то, и то разделится на две операции, вот так:
y=++x => x+=1, y=x
y=x++ => y=x, x+=1
где тут кривые гвозди?


на выходе разное значение Y. и одинаковое значение X
Litkevich Yuriy
Цитата(ЙаМайскЫйПчОЛ @ 23.7.2008, 16:11) *
на выходе разное значение Y. и одинаковое значение X

и в моем примере тоже
ЙаМайскЫйПчОЛ
Litkevich Yuriy, В чем вопрос?
Ты все правильно расписал.
Эта доп переменная, только для сохранения идентичности формы записи в одно выражение типа y=(...);
А если расписывать в две строки, то тогда как у тебя. все верно, я и не спорил)))
void*
Цитата(ЙаМайскЫйПчОЛ @ 23.7.2008, 12:11) *
если логику использования цикла for нельзя выразить через while и do while, то это является свидетельством плохо организованного алгоритма или неверной логики

расписать-то можно, но вот мне например не нравится инкрементную или декрементную операцию выносить в отдельную строку (это если в while)
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2024 IPS, Inc.