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.