Oryginalna strona colobot.cba.pl umarła, gdy cba.pl przestało oferować darmowy hosting. To jest statyczny mirror, pobrany w 2018. ~krzys_h
|
Forum - Polski Portal COLOBOTa |
|
|
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
|
|
|
|
|
|
|
| |
|
|
|
|
Polski Portal COLOBOTa © 2008 - 2012 |
|
|