Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Function/Procedure -Deklaration ?! (https://www.delphipraxis.net/20535-function-procedure-deklaration.html)

fauxx 19. Apr 2004 16:40


Function/Procedure -Deklaration ?!
 
Also diese Frage ist mir jetzt einwenig peinlich:
Ich programmiere zwar erst seit September 2003 mit Delphi, aber ich glaube das sollte ich dan doch wissen:

Wo ist bitte der unterschied zwischen:

Delphi-Quellcode:
procedure name(var: TType);
und
Delphi-Quellcode:
procedure name(const var: TType);
also mit dem schlüsselwort var kenn ich das, aber für was ist const (Konstante das weiß ich, aber bei Functions/Procedures)? Hab ich nämlich schon öfters gesehen...

Tryer 19. Apr 2004 16:46

Re: Function/Procedure -Deklaration ?!
 
Zitat:

Zitat von fauxx
Hab ich nämlich schon öfters gesehen...

Und nie auf die Idee gekommen in die Hilfe zu schauen :gruebel:

Const heist das was man vermuten könnte.. der Paramter wird als Konstante übergeben, man kann also innerhalb der Prozedur nicht schreibend darauf zugreifen sondern den Inhalt nur auslesen.
Die Delphi-Hilfe erklärt die verschiedenen Varianten der Parameterübergabe eigentlich recht gut.

MfG,
Tryer

Muetze1 19. Apr 2004 16:46

Re: Function/Procedure -Deklaration ?!
 
Moin!

Damit wird angegeben, das die Funktion/Procedure diese Variable nicht ändert. Dies wird mit dem Schlüsselwort const vom Compiler sogar sicher gestellt. Damit kannst du dir beim Aufruf einer solchen Funktion sicher sein, das deine übergebene Variable auch nach dem Funktionsaufruf noch den gleichen Inhalt hat.

MfG
Muetze1

maestro 19. Apr 2004 16:51

Re: Function/Procedure -Deklaration ?!
 
Zusätzlich gibt es übrigens auch noch "out" - also const, var und out. const sind in-Parameter, var sind in/out-Parameter und out eben nur out-Parameter :)

fauxx 19. Apr 2004 16:52

Re: Function/Procedure -Deklaration ?!
 
Das habe ich vermutet. Nur wo liegt jetzt der unterschied?? Beim oberen Bsp. ist der rückgabewert ja auch der selbe wie der übergabewert wenn nicht mit var eingeleitet....

oder?!

dummer_info_schüler 19. Apr 2004 17:02

Re: Function/Procedure -Deklaration ?!
 
Vielleicht in dem Beispiel, das du hast, aber es kann ja z-.B. sein
Delphi-Quellcode:
 procedure zaehlen (var c);
 begin
   c:=c+1;
 end;
Das hieße, das c ist als Ausgabewert anders, als der Eingabewert, also variabel.

Hättest du in deiner Prozedur nie an dem c (oder wie auch immer) was geändert, wäre es unerheblich gewesen, ob du var davor schreibst oder nicht.

Hättest du in dem obigen Beispiel statt var aber const geschrieben, hätte es eine Fehlermeldung gegeben!

fauxx 19. Apr 2004 17:06

Re: Function/Procedure -Deklaration ?!
 
Das ist mir schon klar. Aber wenn man jetzt nicht will dass die übergebene Variable geändert wird schreibt man doch einfach kein var davor. Wieso benötigt mann dann nocht const.

Bsp:

Delphi-Quellcode:
procedure Name(var a: Integer);
begin
  a := a + 1;
end;
Hier wird a verändert.

Delphi-Quellcode:
procedure Name(a: Integer);
begin
  a := a + 1;
end;
a bleibt wie es ist...

Delphi-Quellcode:
procedure Name(const a: Integer);
begin
  a := a + 1;
end;
hier bleibt auch a wie es ist.. (oder??)

Muetze1 19. Apr 2004 17:15

Re: Function/Procedure -Deklaration ?!
 
Moin!

Dein letztes Beispiel haut dir der Compiler um die Ohren, er erlaubt es gar nicht eine Zuweisung auf a zu machen. Vielleicht nochmal ein Beispiel:

Delphi-Quellcode:
ExtractFileName(Const AFileName : String): String;
Diese Funktion in der SysUtils holt dir aus dem übergebenen String den reinen Dateinamen heraus - auch wenn da nun noch ein Pfad oder Laufwerk davorsteht. Wenn du nun eine Variable s mit irgendeiner Datei + Pfadangabe hast in deinem Code und du brauchst nun nur den Dateinamen, z.B.

Delphi-Quellcode:
Procedure TForm1.Button1Click(Sender...)
Var
  s : String;
Begin
  If ( OpenDialog1.Execute ) Then
  Begin
    s := OpenDialog1.FileName;

    Label1.Caption := ExtractFileName(s);
 
    Memo1.Lines.LoadFromFile(s);
  End;
End;
Ein Beispiel: Du weisst s die voll qualifizierte Dateiangabe zu, damit du nicht immer den OpenDialog und die etwas langsameren Properties nutzen musst. Nun willst du auf einem Label1 den Dateinamen der aktuell geladenen Datei anzeigen, also ExtractFileName() aufrufen und das Ergebnis zu dem Label. Nun brauchst du aber für das Laden des Inhaltes der Datei in das Memo1 den voll-qualifizierten Dateinamen und daher kann man ja mal ins Grübeln kommen, ob nicht auch ExtractFileName() den übergebenen String maltretiert und nach dem Aufruf nur noch der Dateiname ohne Pfad in s drinne ist. Du kannst dir aber sicher sein, dass dem nicht so ist, weil der Parameter bei ExtractFileName() ist ein Const und daher wird der unter keinen Umständen verändert.

Vor allem ist Const auch eine Sache für den Compiler: Kann ich nun den Wert direkt auf den Stack pushen oder muss ich einen Zeiger auf die Variable nehmen. Z.T. ist es weniger Aufwand/Code den der Compiler bei einem Codeaufruf erzeugt und somit auch z.T. eine geringere Stackbelastung (aber in den seltensten Fällen, da ein Pointer mit 4 Bytes schon recht klein ist...).

MfG
Muetze1

Matze 19. Apr 2004 17:17

Re: Function/Procedure -Deklaration ?!
 
Delphi-Quellcode:
procedure Name(var a: Integer);
begin
  a := a + 1;
end;
Hier wird die Speicheradresse übergeben und a dauerhaft geändert, man kann in der kompletten Unit drauf zugreifen.


Delphi-Quellcode:
procedure Name(a: Integer);
begin
  a := a + 1;
end;
Hier wird eine Kopie von a übergeben und a wird nur innerhalb der Prozedur verändert.


Delphi-Quellcode:
procedure Name(const a: Integer);
begin
  a := a + 1; //Fehler
end;
a bleibt innerhalb der Prozedur konstant und kann nicht verändert werden.

fauxx 19. Apr 2004 17:18

Re: Function/Procedure -Deklaration ?!
 
OK, danke! Das hat meine Frage zu 100% beantwortet!

Pseudemys Nelsoni 19. Apr 2004 17:23

Re: Function/Procedure -Deklaration ?!
 
@fauxx

Zitat:

Das ist mir schon klar. Aber wenn man jetzt nicht will dass die übergebene Variable geändert wird schreibt man doch einfach kein var davor. Wieso benötigt mann dann nocht const.
ganz einfach, wenn du weder var noch const angibst, wird eine temporäre extravariable angelegt. wenn du var/const benutzt wird die variable die du als parameter übergeben hast benutzt.

Luckie 19. Apr 2004 22:43

Re: Function/Procedure -Deklaration ?!
 
Eine Kombination von const und var macht keinen Sinn. Ich weiß noch nicht mal, ob das der Compiler überhaupt akzeptiert. Mir const sagst du ihm der Parameter wird in der Prozedur nicht veränder und mit var sagst du ihm wieder, er soll den Parameter verändern. :?

Hansa 19. Apr 2004 23:19

Re: Function/Procedure -Deklaration ?!
 
Das ist elementar. Sieh Dir das an (und ausprobieren !) :

Delphi-Quellcode:
procedure test (OHNE/CONST/VAR a : integer);
begin
  a := a + 1;
end;

procedure TForm1.Button1Click(Sender: TObject);
var b : integer;
begin
  b := 1;
  test (b);
  showmessage (IntToStr (b));
end;
Const bringt eine Konstante. Keine Änderung/Rückgabewert möglich. OHNE bringt in der Prozedur den Parameter unter, der innerhalb als Variable benutzt werden kann. Aber immer noch kein Rückgabewert. Nach außen nicht sichtbar. 8) VAR schließlich liefert den Wert auch zurück.

Luckie 19. Apr 2004 23:32

Re: Function/Procedure -Deklaration ?!
 
Stichworte wären auch by reference und by value. by refernece heißt, es wird eine Speicherstelle als Parameter übergeben. Wird in der Prozedur der Wert dieser Speicherstelle verändert, bleibt diese Änderung nach verlassen der Prozedur erhalten. Von "zurückgeben" kann man, wenn man es genau nimmt, nicht sprechen. by value bedeutet, dass eine Kopie des Wertes als Parameter an die Prozedur übergeben wird. Und wenn ich die Kopie ändere, hat dies logischerweise keinen Einfluss auf das Original.

Hansa 19. Apr 2004 23:41

Re: Function/Procedure -Deklaration ?!
 
soweit ist das in der Theorie schon richtig. Den Const Parameter habe ich noch nie gebraucht. Im Prinzip reicht Wert (OHNE) und VAR - Parameter. Den CONST kann man mit einer lokalen Variablen selber bauen, sofern der Wert (Input bzw.OHNE Parameter) direkt der lokalen Variablen zugewiesen wird. Der VAR - Prameter liefert den dann. Wie Luckie sagt, sieht das im Speicher dann eben so aus. 8)

Matze 20. Apr 2004 11:00

Re: Function/Procedure -Deklaration ?!
 
Zitat:

Zitat von Luckie
Stichworte wären auch by reference und by value ...

Hab ich doch auch gesagt, was das mit der Speicheradresse angeht. ;)

Luckie 20. Apr 2004 11:15

Re: Function/Procedure -Deklaration ?!
 
Aber du hast die damit verbundenen Begriffe nicht genannt, was ich noch mal nachholen wollte.

sonic 20. Apr 2004 11:23

Re: Function/Procedure -Deklaration ?!
 
Hi Leute,

Soweit ich weiß, ist der Aufruf mit const schneller, da der Compiler nur den Wert übergibt, ohne die Möglichkeit diesen zu ändern. Er legt also auch keine temporäre Lokale Variable an...

Könnte man vielleicht ausmessen mit GetTickCount, und ein paar 1000 Routinenaufrufen...

Wenn jemand Lust und Zeit hat...

Mfg Mike.

Matze 20. Apr 2004 11:33

Re: Function/Procedure -Deklaration ?!
 
Ob das merklich schneller ist bezweifle ich. :gruebel:

Auf jeden Fall benötigt es weniger Speicherplatz...

Muetze1 20. Apr 2004 11:36

Re: Function/Procedure -Deklaration ?!
 
Moin!

Zitat:

Zitat von Matze
Auf jeden Fall benötigt es weniger Speicherplatz...

In wie fern denn das? Wenn du ein VAR hast, dann übergibt er nur einen Pointer, also 4 Byte. Wenn du einen Const hast, dann übergibt er die Parameter auf Stack direkt - dabei aber folgende Regeln:

1. Werte die eine Grösse < 4 Bytes haben, werden trotzdem als DWORD gepusht - wegen dem alignment
2. Werte die die grösser als 4 Bytes sind, werden als Zeiger übergeben (Referenz) und somit sind sie auch nur 4 Bytes gross.

Daher: Wie sollte das weniger Speicherplatz brauchen?

Ob nun Const oder Var - er muss so oder so bei einem Element mit einer Grösse > 4 Bytes einen Zeiger / Referenz auf dieses übergeben, somit ändert sich da nix dran.

MfG
Muetze1

Matze 20. Apr 2004 11:42

Re: Function/Procedure -Deklaration ?!
 
Wenn du das var voranstellst, dann wird einfach die Speicheradresse überschreiben, das braucht natürlich nicht mehr Speicher, aber ohne das var wird ja eine Kopie der Variable angelegt, somit sollte das dann etwas mehr Speicherplatz verbrauchen.

Das mit den 4 Bytes stimmt, wenn man const und var betrachtet, aber ohne diese beiden müsste es theoretisch doch mehr verbrauchen. :gruebel:

Oder nicht?

Muetze1 20. Apr 2004 13:06

Re: Function/Procedure -Deklaration ?!
 
Moin!

Zitat:

Zitat von Matze
..., aber ohne das var wird ja eine Kopie der Variable angelegt, ...

Bei Const doch grundlegend auch, wenn die Variable eine Grösse > 4 Bytes hat.

MfG
Muetze1

maximov 20. Apr 2004 13:24

Re: Function/Procedure -Deklaration ?!
 
Zitat:

Zitat von Muetze1
Moin!

Zitat:

Zitat von Matze
..., aber ohne das var wird ja eine Kopie der Variable angelegt, ...

Bei Const doch grundlegend auch, wenn die Variable eine Grösse > 4 Bytes hat.

MfG
Muetze1

Nö, warum denn? Hauptsache der wert kommt an und das tut er auch per reference. Das er read-only ist, darum kümmert sich lediglich der compiler, der dann nämlich aussteigt.

Übrigens kann man const-paras deshalb sehr wohl beschreiben, wenn man bischen mit ^ und @ rumspielt:

Delphi-Quellcode:
type
  pPoint = ^TPoint;

procedure Foo(const bar:TPoint);
begin
   pPoint(@bar)^ := Point(10,20);
end;


procedure TForm1.Button1Click(Sender: TObject);
var c:TPoint;
begin
  c := Point(0,0);
  foo(c);
  ShowMessage(intToStr(c.X)+','+intToStr(c.Y));
end;
Allerdings nur bei werten > 4 byte...oder so!

sonic 20. Apr 2004 15:00

Re: Function/Procedure -Deklaration ?!
 
Hallo Leute

Habe eure Diskussion verfolgt. Folgendes macht Delphi bei den Übergabeattributen:

Fall 1:
Code:
procedure Test(a: string) -> call by value
Fall 2:
Code:
procedure Test(const a: string) -> call by reference
Fall 3:
Code:
procedure Test(var a: string) -> call by reference
Beim Fall 1 wird der String als "call by Value" übergeben. Da es sich hierbei um einen string = (Objekt) handelt, sind einige Maschinencodeanweisungen notwendig. Wenn man im FPU-Debugger die erzeugten Anweisungen ansieht, kommen dabei um die 30 Assembleranweisungen zusammen.

Beim Fall 2 und 3 wird der String als "call by reference" übergeben. Dabei handelt es sich nur mehr um die Speicheradresse der Variablen (4 Byte), die über den Stack übergeben wird. Dafür ist nur mehr eine Maschinencodeanweisung notwendig. Geschwindigkeitsmäßig sollten Fall 2 und Fall 3 gleich schnell sein.

(Informationen stammen von meinem Persönlichen Delphi Lehrer)

Mfg Mike.

PS. Habe mich also geirrt, Const ist schneller als ohne was, aber nicht schneller als var... :wall:

Muetze1 20. Apr 2004 15:34

Re: Function/Procedure -Deklaration ?!
 
Moin!

Ok, ich habe das ganze jetzt nochmal debuggt und folgendes kam dabei raus: alle 3 Formen haben ein und die selbe Übergabeform:

EAX = Self der Form
EDX = Zeiger auf den String

Die Funktionen sind alle gleich vom Aufruf her - was durch den Variablentyp mit einer Grösse > 4 auch kein Wunder ist - vor allem wird bei Strings so oder so nur mit einer Instanzenaddresse gearbeitet.

Code:
  push ebp
  mov ebp, esp
  add esp, -$08  // Platz für 2x 4 Byte machen - sichern der Var's
  mov [ebp-$08], edx // String sichern auf'm Stack
  mov [ebp-$04], eax // Instanzenzeiger sichern auf'm Stack
 
  // hier ist ein Unterschied - siehe unten

  mov edx, [ebp-$08] // String holen
  mov eax, [ebp-$04] // Instanzenzeiger holen
  call Trim

...
Der Unterschied besteht bei der 1. Funktion wo kein Const und kein Var angeben wurde, dort wird vor dem Aufruf von Trim() sicher gestellt, dass es keine anderen Referenzen auf den String gibt - also wird, wenn eine Referenz da ist, diese abgespalten in einen eigenen String. Danach wird der eindeutige String nach dem Trim gelöscht - also Referenz entfernen und String löschen. Mit anderen Worten: Bei der ersten Form wird vorher keine Kopie von dem String gemacht, das macht die Funktion selber, wenn nötig - also wenn es mehr als eine Referenz auf den String gibt.

Mein Testcode dazu (Optimierung aus, sonst kann man das nicht so schön sehen)
Code:
Function Test1(AStr : String): String;
Begin
  Result := Trim(AStr);
End;

Function Test2(Const AStr : String): String;
Begin
  Result := Trim(AStr);
End;

Function Test3(Var AStr : String): String;
Begin
  Result := Trim(AStr);
End;

procedure TForm1.FormCreate(Sender: TObject);
Var
  s : String;
begin
  s := Edit1.Text;

  Label1.Caption := Test1(s);
  Label2.Caption := Test2(s);
  Label3.Caption := Test3(s);
end;
Zusammenfassung:

Die Aufrufart ohne Const oder Var sorgt für grösseren Code für die Duplizierung / Dereferenzierung. Die anderen beiden Arten sind völlig gleich. Und wohl gemerkt ist trotz des Unterschiedes kein Unterschied zwischen der by value oder by reference Übergabe zu sehen, weil die Übergabe der Parameter geschieht komplett gleich - die by reference Geschichte wird von der Funktion selber sicher gestellt.

MfG
Muetze1

Matze 20. Apr 2004 17:01

Re: Function/Procedure -Deklaration ?!
 
Danke, dass du dir die Mühe gemacht hast, find ich echt klasse! :thumb:

Nur verstehe ich's immer noch nicht genau. :-?
Ist zwar Off-Topic, aber auch net so ganz. ;)

NicoDE 20. Apr 2004 17:14

Re: Function/Procedure -Deklaration ?!
 
Zitat:

Zitat von Muetze1
Die Aufrufart ohne Const oder Var sorgt für grösseren Code für die Duplizierung / Dereferenzierung. Die anderen beiden Arten sind völlig gleich. Und wohl gemerkt ist trotz des Unterschiedes kein Unterschied zwischen der by value oder by reference Übergabe zu sehen, weil die Übergabe der Parameter geschieht komplett gleich - die by reference Geschichte wird von der Funktion selber sicher gestellt.

Nur mal so als Anregung: mach das mal mit ShortString (bzw. anderen Strukturen ohne integrierten Referenzzähler).

Muetze1 20. Apr 2004 20:58

Re: Function/Procedure -Deklaration ?!
 
Moin!

Mir ist ja wirklich schlecht geworden, als ich das mal mit einem ShortString gemacht habe...

Die Ergebnisse:

1. Ohne Var oder Const packt er den kompletten ShortString auf den Stack! (also wenn das keine Verschwendung ist, aber wir haben's ja unter Windows)
2. Mit einem Const das gleiche, nur da ist es fast noch schlimmer: die Funktion kopiert sich von dem ShortString, der auch hier komplett auf dem Stack liegt, eine Kopie in die Stackframe. Mit anderen Worten der Stack in der Funktion sieht dann so aus, dass er einmal den kompletten ShortString als Param liegen hat auf'm Stack beim Eintritt. Dann besorgt er sich nochmal 256 Bytes Platz auf dem Stack (ESP verschieben) und kopiert in den neuen Platz den String von weiter vorne. Dann nutzt er bei den weiteren Funktionen die Kopie.
3. Die Var - Variante bekommt eine Referenz / Zeiger auf den String übergeben.

Fazit: Nur die Var Methode dürfte in so fern schneller sein und vor allem Stack-freundlicher.
Abhilfe: keinen ShortString verwenden, sondern einen AnsiString/String, der kann Referenzen....

MfG
Muetze1


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:26 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz