Oryginalna strona colobot.cba.pl umarła, gdy cba.pl przestało oferować darmowy hosting. To jest statyczny mirror, pobrany w 2018. ~krzys_h
 Polski Portal COLOBOTa - COLOBOT Polish Portal
Forum - Polski Portal COLOBOTa
Strona głównaStrona główna UżytkownicyUżytkownicy GrupyGrupy StatystykiStatystyki


Poprzedni temat «» Następny temat
Różnica między ++x a x++
Autor Wiadomość
Simbax 
Mod


Twoja ulubiona misja: Wszystkie na Krystalii
Pomógł: 6 razy
Wiek: 22
Dołączył: 07 Sie 2009
Posty: 473
Skąd: z Leszna
Wysłany: 31-01-2011, 19:44   Różnica między ++x a x++

Zrobiłem sobie mały eksperymencik. Napisałem taki oto programik:
Kod:

int a, b, c;

    a=1;
    b=2;
    c=3;
   
    a = ++a;
    b = ++c;
    c = b++;
   
    cout << "a = " << a << endl << "b = " << b << endl << "c = " << c;
    getch();

    return 0;


Modyfikowałem parę razy ustawienie. Wyniki mnie zaskoczyły. Wg. mojego niekumatego mózgu powinno wyjść: a=2; b=4; c=5. Wyszło: a=2; b=5; c=4. What the hell? Jaka jest różnica między ustawieniem plusów? Czemu takie wyniki? Głowa mnie boli.
_________________
http://projektsimbax.blogspot.com/ <- Taki sobie blog
 
     
Berserker 
Dark Ness


Twoja ulubiona misja: Ofrenia
Pomógł: 16 razy
Wiek: 24
Dołączył: 24 Mar 2009
Posty: 496
Skąd: Bigos
Wysłany: 31-01-2011, 19:51   

Roznica miedzy ++i a i++ jest taka, ze w ++i inkrementacja jest wykonywana przed wszystkimi operacjami, a w i++ dopiero po wykonaniu innych operacji. Czyli:

Kod:

a = ++a; // a zwiekszamy do 3
b = ++c; // c zwiekszamy do 4, po czym kazemy b przyjac wartosc c, czyli 4.
c = b++ // c przyjmuje wartosc b, czyli 4, po czym b zwiekszamy o 1, dzieki czemu ma wartosc 5.

Mam nadzieje, ze pomoglem :>
_________________
 
 
     
Simbax 
Mod


Twoja ulubiona misja: Wszystkie na Krystalii
Pomógł: 6 razy
Wiek: 22
Dołączył: 07 Sie 2009
Posty: 473
Skąd: z Leszna
Wysłany: 31-01-2011, 19:57   

Jezu nie sądziłem, że to takie proste. Już rozumiem, dziękuje bardzo. Masz punkta :->
_________________
http://projektsimbax.blogspot.com/ <- Taki sobie blog
 
     
COLOBOT 
Administrator sieci
Założyciel portalu


Twoja ulubiona misja: Obie na Orfenii
Pomógł: 1 raz
Dołączył: 07 Lut 2008
Posty: 353
Skąd: Jarocin
Wysłany: 20-04-2011, 17:16   

Trochę odkop, ale dodam, że wersja preinkrementacyjna (++zmienna) podobno jest szybsza. Tak więc jeśli zależy wam mocno na optymalizacji czasu, plusiki lub minusiki należy stawiać wcześniej (o ile nie zmieni to działania programu).
_________________
Bykom STOP
A niechaj narodowie wżdy postronni znają, iż Polacy nie gęsi, iż swój język mają.
 
 
     
Berserker 
Dark Ness


Twoja ulubiona misja: Ofrenia
Pomógł: 16 razy
Wiek: 24
Dołączył: 24 Mar 2009
Posty: 496
Skąd: Bigos
Wysłany: 20-04-2011, 17:36   

Podobno? A z czego to wynika?
_________________
 
 
     
COLOBOT 
Administrator sieci
Założyciel portalu


Twoja ulubiona misja: Obie na Orfenii
Pomógł: 1 raz
Dołączył: 07 Lut 2008
Posty: 353
Skąd: Jarocin
Wysłany: 20-04-2011, 19:52   

Najprawdopodobniej chodzi tu o ilość odwołań do pamięci, ale głowy nie dam.
_________________
Bykom STOP
A niechaj narodowie wżdy postronni znają, iż Polacy nie gęsi, iż swój język mają.
 
 
     
adiblol 
Administrator forum
FLOSS FTW!


Twoja ulubiona misja: porównywanie formatów audio
Pomógł: 18 razy
Dołączył: 21 Kwi 2008
Posty: 1313
Skąd: pokój odsłuchowy
Wysłany: 20-04-2011, 21:09   

W pseudokodzie:

++x:
x += 1
RESULT = x
return RESULT

x++:
RESULT = x
x += 1
return RESULT

Teoretycznie robienia po pamięci tyle samo... zwłaszcza że to x86 czyli CISC... czyli w asemblerze możemy sobie zrobić bezczelnie "add x, 1" czy "inc x", nie trzeba najpierw zapisywać do rejestru a potem z powrotem do pamięci (jak to chyba ma miejsce w ARMach).

Jednak pomyślmy o tym w następującej kategorii: czy trzeba zapisywać RESULT jako oddzielną zmienną? Więc pierwsze można uprościć:
++x:
x += 1
return x

Drugie - niebardzo.

Na pocieszenie: nowoczesny kompilator (gcc) zamieni pojedynczą instrukcję inkrementacji która nie zwraca wartości na jak najprostszą:
++x:
x += 1

x++:
x += 1



------------------------------------------------------------------------------------

Sprawa mnie zainteresowała więc do pracy wciągnąłem GDB:
Dla "x++" napisałem taki kod:
Kod:
int main() {
    int x, y;
    x=0xdeadbeef;
    y = x++;
    x=0xdeadbeef;
    return 0;
}

A oto wynik deasemblacji:
Kod:
Dump of assembler code for function main:
   0x08048394 <+0>:    push   %ebp
   0x08048395 <+1>:    mov    %esp,%ebp
   0x08048397 <+3>:    sub    $0x10,%esp
=> 0x0804839a <+6>:    movl   $0xdeadbeef,-0x4(%ebp)
   0x080483a1 <+13>:    mov    -0x4(%ebp),%eax
   0x080483a4 <+16>:    mov    %eax,-0x8(%ebp)
   0x080483a7 <+19>:    addl   $0x1,-0x4(%ebp)
   0x080483ab <+23>:    movl   $0xdeadbeef,-0x4(%ebp)
   0x080483b2 <+30>:    mov    $0x0,%eax
   0x080483b7 <+35>:    leave 
   0x080483b8 <+36>:    ret   

Składnia jest AT&T czyli addl a, b to to samo co b += a. Tak samo jest jakby odwrotnie niż w klasycznym asemblerze z funkcją mov.

I co my tu mamy:
przypisywanie 0xdeadbeef to "markery" żebyśmy byli pewni gdzie się zaczyna i kończy nasz kod.
Najpierw kopiowany jest x do y (z pośrednictwem eax), następnie x jest powiększany o 1.

Sprawdźmy alternatywny kod...
Kod:
int main() {
    int x, y;
    x=0xdeadbeef;
    y = ++x;
    x=0xdeadbeef;
    return 0;
}


Kod:
Dump of assembler code for function main:
   0x08048394 <+0>:    push   %ebp
   0x08048395 <+1>:    mov    %esp,%ebp
   0x08048397 <+3>:    sub    $0x10,%esp
=> 0x0804839a <+6>:    movl   $0xdeadbeef,-0x4(%ebp)
   0x080483a1 <+13>:    addl   $0x1,-0x4(%ebp)
   0x080483a5 <+17>:    mov    -0x4(%ebp),%eax
   0x080483a8 <+20>:    mov    %eax,-0x8(%ebp)
   0x080483ab <+23>:    movl   $0xdeadbeef,-0x4(%ebp)
   0x080483b2 <+30>:    mov    $0x0,%eax
   0x080483b7 <+35>:    leave 
   0x080483b8 <+36>:    ret   

Tutaj najpierw jest dodawane 1 do x a później kopiowane (z pośrednictwem eax znowu) do y. Złożoności obliczeniowej w tym konkretnym przypadku to nie zmienia. Nie będę rozpatrywał jakichś ambitniejszych algorytmów bo to nie ma sensu - zależnie od tego czy mamy ++x czy x++ zmienia się wynik.


A teraz przy braku przypisania do y, x++:
Kod:
int main() {
    int x, y;
    x=0xdeadbeef;
    x++;
    x=0xdeadbeef;
    return 0;
}

...i ++x:
Kod:
int main() {
    int x, y;
    x=0xdeadbeef;
    ++x;
    x=0xdeadbeef;
    return 0;
}


Wygenerowane przez kompilator (z wyłączoną optymalizacją!) kody są... identyczne.
Kod:
Dump of assembler code for function main:
   0x08048394 <+0>:    push   %ebp
   0x08048395 <+1>:    mov    %esp,%ebp
   0x08048397 <+3>:    sub    $0x10,%esp
=> 0x0804839a <+6>:    movl   $0xdeadbeef,-0x4(%ebp)
   0x080483a1 <+13>:    addl   $0x1,-0x4(%ebp)
   0x080483a5 <+17>:    movl   $0xdeadbeef,-0x4(%ebp)
   0x080483ac <+24>:    mov    $0x0,%eax
   0x080483b1 <+29>:    leave 
   0x080483b2 <+30>:    ret   

Kod:
Dump of assembler code for function main:
   0x08048394 <+0>:    push   %ebp
   0x08048395 <+1>:    mov    %esp,%ebp
   0x08048397 <+3>:    sub    $0x10,%esp
=> 0x0804839a <+6>:    movl   $0xdeadbeef,-0x4(%ebp)
   0x080483a1 <+13>:    addl   $0x1,-0x4(%ebp)
   0x080483a5 <+17>:    movl   $0xdeadbeef,-0x4(%ebp)
   0x080483ac <+24>:    mov    $0x0,%eax
   0x080483b1 <+29>:    leave 
   0x080483b2 <+30>:    ret   
End of assembler dump.


We wszystkich testach optymalizacja została wyłączona.

Reasumując - jeśli inkrementacja jest pojedynczą instrukcją której zwracana wartość nie jest nigdzie potrzebna to wszystko jedno.
_________________
1Tbps Project && Telecomix Network

 
 
     
Wyświetl posty z ostatnich:   

Wersja do druku

Skocz do:  

Powered by phpBB modified by Przemo © 2003 phpBB Group
Polski Portal COLOBOTa © 2008 - 2012