Einzelnen Beitrag anzeigen

Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#55

AW: Procedure vs Function, Vor- und Nachteile

  Alt 16. Apr 2018, 17:27
Schick mir bitte einen Link, wo du dazu infos findest. Denn das DocWiki liefert hierzu nämlich nichts verwertbares. Ich versuche schon seit Jahren, dahinter zu kommen, WIE genau const den Parameterzugriff wann optimiert. Und zu den Referenzen: Das DicWiki sagt tatsächlich auch hier nur, dass es so ist, wie ich beschrieb. Ob es da Ausnahmen gibt, keine Ahnung. Auch hier wäre ich für mein Selbstsstudium um eine Informationsquelle sehr dankbar!
Puh, das sind alles Informationen, die ich im Laufe der Jahre aus verschiedenen Quellen und durch Beobachtung zusammengetragen habe. Also insbesondere zum const kann ich dir sagen, dass Records bis 4/8 Byte (je nach 32- bzw. 64-bit) direkt übergeben werden (da die Werte ja dann direkt in ein Register bzw. auf den Stack passen) und erst danach werden (meistens) Referenzen verwendet. Dazu steht im Wiki:
Zitat:
Constant parameters may be passed to the function by value or by reference, depending on the specific compiler used. To force the compiler to pass a constant parameter by reference, you can use the [Ref] decorator with the const keyword.

Bezüglich Strings habe ich mal ein paar Tests gemacht:

Testfunktionen:
Delphi-Quellcode:
procedure Test1(S: String);
begin
  ShowMessage(S);
end;

procedure Test2(const S: String);
begin
  ShowMessage(S);
end;

procedure Test3(var S: String);
begin
  ShowMessage(S);
end;
Aufrufe (alles Referenzen):
Code:
Unit2.pas.45: Test1(S);
005CE35C 8B45F8           mov eax,[ebp-$08]
005CE35F E85CFFFFFF      call Test1
Unit2.pas.46: Test2(S);
005CE364 8B45F8           mov eax,[ebp-$08]
005CE367 E89CFFFFFF      call Test2
Unit2.pas.47: Test3(S);
005CE36C 8D45F8           lea eax,[ebp-$08]
005CE36F E8A8FFFFFF      call Test3
Test1:
Code:
Unit2.pas.26: begin
005CE2C0 55               push ebp
005CE2C1 8BEC            mov ebp,esp
005CE2C3 51               push ecx
005CE2C4 8945FC          mov [ebp-$04],eax
005CE2C7 8B45FC          mov eax,[ebp-$04]
005CE2CA E891BAE3FF      call @UStrAddRef
005CE2CF 33C0             xor eax,eax
005CE2D1 55               push ebp
005CE2D2 68FBE25C00       push $005ce2fb
005CE2D7 64FF30           push dword ptr fs:[eax]
005CE2DA 648920           mov fs:[eax],esp
Unit2.pas.27: ShowMessage(S);
005CE2DD 8B45FC          mov eax,[ebp-$04]
005CE2E0 E8BB9DF7FF      call ShowMessage
Unit2.pas.28: end;
005CE2E5 33C0             xor eax,eax
005CE2E7 5A              pop edx
005CE2E8 59               pop ecx
005CE2E9 59               pop ecx
005CE2EA 648910           mov fs:[eax],edx
005CE2ED 6802E35C00       push $005ce302
005CE2F2 8D45FC          lea eax,[ebp-$04]
005CE2F5 E882B9E3FF      call @UStrClr
005CE2FA C3               ret
005CE2FB E998AFE3FF      jmp @HandleFinally
005CE300 EBF0             jmp $005ce2f2
005CE302 59               pop ecx
005CE303 5D              pop ebp
005CE304 C3               ret
Test2:
Code:
Unit2.pas.31: begin
005CE308 55               push ebp
005CE309 8BEC            mov ebp,esp
005CE30B 51               push ecx
005CE30C 8945FC          mov [ebp-$04],eax // danke dafür :D
Unit2.pas.32: ShowMessage(S);
005CE30F 8B45FC          mov eax,[ebp-$04] // danke dafür :D
005CE312 E8899DF7FF      call ShowMessage
Unit2.pas.33: end;
005CE317 59               pop ecx
005CE318 5D              pop ebp
005CE319 C3               ret
Test3:
Code:
Unit2.pas.36: begin
005CE31C 55               push ebp
005CE31D 8BEC            mov ebp,esp
005CE31F 51               push ecx
005CE320 8945FC          mov [ebp-$04],eax
Unit2.pas.37: ShowMessage(S);
005CE323 8B45FC          mov eax,[ebp-$04]
005CE326 8B00             mov eax,[eax]
005CE328 E8739DF7FF      call ShowMessage
Unit2.pas.38: end;
005CE32D 59               pop ecx
005CE32E 5D              pop ebp
005CE32F C3               ret
Hier sieht man schon ganz schön, wie viel Overhead man hat, wenn kein const/var/out verwendet wird. Ref-Counter, SEH, etc. Jetzt modifiziere ich mal Test1 und Test3 , so dass geschrieben statt gelesen wird.

Testfunktionen:
Delphi-Quellcode:
procedure Test1(S: String);
begin
  S := '123';
end;

procedure Test3(var S: String);
begin
  S := '123';
end;
Aufrufe (weiterhin alles Referenzen):
Code:
Unit2.pas.50: Test1(S);
005CE350 8B45F8           mov eax,[ebp-$08]
005CE353 E840FFFFFF      call Test1
Unit2.pas.51: Test3(S);
005CE358 8D45F8           lea eax,[ebp-$08]
005CE35B E898FFFFFF      call Test3
Test1:
Code:
Unit2.pas.26: begin
005CE298 55               push ebp
005CE299 8BEC            mov ebp,esp
005CE29B 51               push ecx
005CE29C 8945FC          mov [ebp-$04],eax
005CE29F 8B45FC          mov eax,[ebp-$04]
005CE2A2 E8B9BAE3FF      call @UStrAddRef
005CE2A7 33C0             xor eax,eax
005CE2A9 55               push ebp
005CE2AA 68D8E25C00       push $005ce2d8
005CE2AF 64FF30           push dword ptr fs:[eax]
005CE2B2 648920           mov fs:[eax],esp
Unit2.pas.27: S := '123';
005CE2B5 8D45FC          lea eax,[ebp-$04] // hier beginnt der copy-on-write Teil
005CE2B8 BAF0E25C00       mov edx,$005ce2f0
005CE2BD E8E2BDE3FF      call @UStrLAsg
Unit2.pas.28: end;
005CE2C2 33C0             xor eax,eax
005CE2C4 5A              pop edx
005CE2C5 59               pop ecx
005CE2C6 59               pop ecx
005CE2C7 648910           mov fs:[eax],edx
005CE2CA 68DFE25C00       push $005ce2df
005CE2CF 8D45FC          lea eax,[ebp-$04]
005CE2D2 E8A5B9E3FF      call @UStrClr // Kopie freigeben
005CE2D7 C3               ret
005CE2D8 E9BBAFE3FF      jmp @HandleFinally
005CE2DD EBF0             jmp $005ce2cf
005CE2DF 59               pop ecx
005CE2E0 5D              pop ebp
005CE2E1 C3               ret
Test3:
Code:
Unit2.pas.36: begin
005CE2F8 55               push ebp
005CE2F9 8BEC            mov ebp,esp
005CE2FB 51               push ecx
005CE2FC 8945FC          mov [ebp-$04],eax
Unit2.pas.37: S := '123';
005CE2FF 8B45FC          mov eax,[ebp-$04]
005CE302 BA1CE35C00       mov edx,$005ce31c
005CE307 E850BDE3FF      call @UStrAsg
Unit2.pas.38: end;
005CE30C 59               pop ecx
005CE30D 5D              pop ebp
005CE30E C3               ret
Auch hier ist die Funktion mit const deutlich kompakter.
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat