Witam.
Chodzi o sytuację, w czasie której dostałem ochrzan od swojego wykładowcy za zastosowanie takiego zapisu:
for(int i = 1; i < 10; i = i + 1)
Postanowiłem bardziej zbadać zagadnienie i sprawdzić jak sprawa ma się w rzeczywistości.
Czy te operacje różnią się między sobą w kodzie maszynowym, czy też nie?
A co z innymi operatorami:
W tym wypadku postanowiłem stworzyć kod szablonowy w programie C++Builder XE2 kompilowanym na procesory 80836 wyglądający następująco:
int main()
{
for(int i = 1; i < 10; i++)
{
std::cout << i;
}
return 0;
}
Oczywśicie instrukcja kroku pętli przy każdym z testów została zmieniana odpowiednio.
I tak. W przypadku zapisu
for(int i = 1; i < 10; i++)
Deasemblowany kod wyglądał następująco
push ebp ; int main()
mov ebp,esp
push ecx
mov [ebp-$04],$00000001 ; for(int i = 1; i < 10; i++)
push dword ptr [ebp-$04] ; std::cout << i;
push dword ptr [$00409208]
call std::basic_ostream<char, std::char_traits<char> >::operator <<(int)
add esp,$08
inc dword ptr [ebp-$04] ; for(int i = 1; i < 10; i++)
cmp dword ptr [ebp-$04],$0a
jl $00401173
Dla zapisu
for(int i = 1; i < 10; ++i)
Deasemblowany kod wyglądał następująco
push ebp ; int main()
mov ebp,esp
push ecx
mov [ebp-$04],$00000001 ; for(int i = 1; i < 10; ++i)
push dword ptr [ebp-$04] ; std::cout << i;
push dword ptr [$00409208]
call std::basic_ostream<char, std::char_traits<char> >::operator <<(int)
add esp,$08
inc dword ptr [ebp-$04] ; for(int i = 1; i < 10; ++i)
cmp dword ptr [ebp-$04],$0a
jl $00401173
Dla zapisu
for(int i = 1; i < 10; i = i + 1)
Deasemblowany kod wyglšdał następująco
push ebp ; int main()
mov ebp,esp
push ecx
mov [ebp-$04],$00000001 ; for(int i = 1; i < 10; i = i + 1)
push dword ptr [ebp-$04] ; std::cout << i;
push dword ptr [$00409208]
call std::basic_ostream<char, std::char_traits<char> >::operator <<(int)
add esp,$08
inc dword ptr [ebp-$04] ; for(int i = 1; i < 10; i = i + 1)
cmp dword ptr [ebp-$04],$0a
jl $00401173
Dla zapisu
for(int i = 1; i < 10; i+= 1)
Deasemblowany kod wyglądał następująco
push ebp ; int main()
mov ebp,esp
push ecx
mov [ebp-$04],$00000001 ; for(int i = 1; i < 10; i+= 1)
push dword ptr [ebp-$04] ; std::cout << i;
push dword ptr [$00409208]
call std::basic_ostream<char, std::char_traits<char> >::operator <<(int)
add esp,$08
inc dword ptr [ebp-$04] ; for(int i = 1; i < 10; i+= 1)
cmp dword ptr [ebp-$04],$0a
jl $00401173
Każdy na pierwszy rzut oka dostrzega, że nie ma żadnej różnicy pomiędzy tymi 4 skompilowanymi kodami.
We wszystkich przypadkach otrzymałem dokładnie ten sam kod po deasemblacji. Wniosek mam z tego taki, że niezależnie jaki zapis wybiorę do dodania wartości do zmiennej to i tak mój kompilator uzna go za taki sam.
Zrobiłem również mały zwiad wśród osób, które znają się wiele lepiej ode mnie na programowaniu i dowiedziałem się, że technicznie najszybszym zapisem dla komputera powinno być ++i (które powinno być najbardziej zoptymalizowane ze wszystkich tych zapisów).
++i ma mieć szybsze, bardziej optymalne działanie z tego powodu, że assembler w przypadku i++ tworzy obiekt tymczasowy, który dostanie wartość zmiennej i, a później zwiększy mu wartość o 1 i na koniec przypisze otrzymany wynik do zmiennej i.
Jednak najwięcej zależy od samego kompilatora. Doskonałym tego przykładem jest ten post:
http://gynvael.coldwind.pl/?id=369
który obrazuje wynik działania instrukcji:
int a = 5;
a = a++ + ++a;
a = ?
Wniosek, jaki się nasuwa po przeprowadzeniu tego testu jest taki, że technicznie wszystkie te zapisy są takie same, mogą one się różnić na różnych kompilatorach, ale bazując na tym jednym mogę stwierdzić, że nie robi mu różnicy jaki zapis zostanie użyty, a stosowanie którego z tych zapisów jest kwestią czysto estetyczną.
Jednak czytając post na blogu Gynvaela można dostrzec pewne wady zapisu i++ i ++i w wyrażeniach.