![]() |
Zitat:
[================================================] Dieser Thread wurde von folgendem Thread abgetrennt, da die Inhalte beide diskussionswürdig sind, allerdings verschieden Voraussetzungen mit sich bringen. ![]() Mit freundlichen Grüßen, SAKURA |
Zitat:
Ich quotiere doch glatt noch einmal den Delphi-Language Guide: Zitat:
...:cat:... |
Ach du Schande, Sakura bringt tatsächlich die Grammatik. Hätte ich das vorher gewußt. :mrgreen:
Aber was hindert einen daran, den VAR Paramter als Rückgabewert zu benutzen. Wie bei einer Funktion :?: |
Wie gesagt, ich habe geschreiben, das man var-Parameter nutzen kann, aber das sind keine Prozedur-Rückgabe werden, es sind halt "[in|out] Parameter", welche einen Rückgabewert aufnehmen kann. Es ist ein kleiner, feiner Unterschied.
...:cat:... |
Dann schreibe doch wenigstens, warum. :shock: Man kann eine Prozedur nicht so übergeben:
Delphi-Quellcode:
Pseudocode halt :mrgreen:
var i : integer;
i := procedure Iwert aber schon als i := IFunction, wobei: Function IFunction : integer; |
Hansa, Du hast mit Deinem Ansatz aber völlig am Problem vorbei manövriert. Es geht hier um "Prozedurvariablen", welche eigentlich Pointer sind. Damit würde auch folgender Code problemlos gehen (Zuweisung einer Prozedur auf eine "Prozedurvariable")
Delphi-Quellcode:
Dabei wird Owhm F zugewiesen. Oehm ist eine Prozedur.
procedure Oehm(X, C: Integer);
begin ShowMessage(IntToStr(X + C)); end; procedure TForm1.Button1Click(Sender: TObject); var F: procedure (A, B: Integer); begin F := Oehm; F(1, 2); end; ...:cat:... |
Worum gehts denn hier eigentlich noch? Sicher doch nicht um den unterschied zwischen Funktionen (gibt einen Funktionswert zurück) und Prozeduren (gibt keinen Funktionswert zurück).
Das ist doch wieder so ein Punkt den C-Programmierer nehemn um Pascal bzw Delphi schlecht zumachen. Denn sie meinen es ist verwirrend da zu unterscheiden, immerhin gibt es in C ja nur Funktionen (mit und ohne Rückgabewert). Was die Parameterübergabe bei Prozeduren angeht, da sollte man erstmal in die Online Hilfe schauen :-) Stichwort: Parameter |
Zitat:
|
Das sind aber Parameter! da steckt ein andere Mechanismus hinter.
In Delphi gibt es 4 Parameterformen (Wert-, (Var) Variablen-, (const) Konstanten- oder (out) Ausgabeparameter) sie geben an wie die Variablen in der Routine behandelt wird. Bei VAR-Parametern wird KEINE neue Variable erzeugt, wie bei den anderen. im Prinzip wird nur ein Zeiger übergeben. Somit haben verönderungen in der Subroutine direkte Auswirkungen auf die Variable. Im Prinzip würde das auch bei Funktionen gehen. Aber Borland hat das eben nicht so vorgesehen. |
Zitat:
|
@Hansa
Ich weis ja nicht was du genau willst. Aber bei der Übergabe von normalen Parametern in Delphi/Pascal wird (vom compiler, also im Hintergrund) eine neue lokale Variable, also ein Integer oder String ...) für die SubRoutine erzeugt. Wenn Das steuerwort var benutzt wird ist das nicht der Fall. Naja fast, es wird nur ein Zeiger erzeugt der auf die Variable in der übergeordneten Routine zeigt. Wie gesagt bekommt der Programmierer davon nichts mit. Was du mit Zitat:
|
ich verstehe das genauso wenig, wie Du. 8) Wenn ich folgenden Code habe:
Delphi-Quellcode:
was steht dann hier drin ? :
procedure Test (VAR i : integer);
begin i := 5; end;
Delphi-Quellcode:
begin
showmessage (IntToStr (Test (8)); end; |
Du meinst wie ShowMessage deklariert ist?
Delphi-Quellcode:
kannst du auch selber nachschauen :-)
procedure ShowMessage(const Msg: string);
Edit: Ich versteh nicht ganz worauf du hinaus willst |
Delphi-Quellcode:
was steht dann hier drin ? :
unit TestUnit;
Interface procedure Test (VAR i : integer); implementation procedure Test (VAR i : integer); begin i := 5; end; end;
Delphi-Quellcode:
??????
program TestProgramm;
uses TestUnit,..... begin showmessage (IntToStr (Test (8)); end; |
Könntest du dich bitte so ausdrücken das man versteht was du willst?
Irgendwelchen kommentarlosen Quelltext posten nenne ich nicht verständlich oder klar ausdrücken. Und ein "was steht dann hier drin ? :" bringt es auch nicht wirklich. :roll: Eventuell bin ich ja schwer von Begriff, also hab Verständnis. |
Viel einfacher gehts wirklich nicht. :|
Das ist wahrscheinlich eines der kleinsten Programme der Welt. Mir fällt jedenfalls nicht ein, wie es noch kleiner werden könnte. Läßt Du das Programm laufen, was wird dann angezeigt? 5 oder 8 ??? Das ist ein Rätsel, wo die Lösung gleich mitgeliefert wird. :mrgreen: |
Es wird gar nichts angezeigt, denn du kannst das Programm nicht kompilieren. InttoStr() erwartet als Parameter einen Integer, die Prozedur gibt aber keinen Integer als Rückgabewert zurück.
Sie hat keinen Rückgabewert. |
Zitat:
Code:
Wieso ist da kein Rückgabewert ???
procedure Test (VAR i : integer);
begin i := 5; end; |
1. "was steht dann hier drin ? :" Sagt für mich nicht aus, dass ich Dir sagen soll was nach ausführen deines Programm-Codes af dem Bildschirm ausgegeben wird.
2. ist dein Quelltext fehlerhaft! Ausser du bringst Delphi bei, Zahlen als Variablennamen zu interpretieren. Du kannst einer Prozedur die ein Var-Parameter verlangt keinen Zahlenwert übergeben. Meinen perönlichen Kommentar verkeif ich mir mal. :| |
Zitat:
"Rückgabewert" bedeutet, dass die Rückgabe der Funktion nach Ablauf des Programmblocks (=Funktion) in das Register EAX geschrieben wird. Bei einer Funktion ist da was drin, bei einer Prozedurr wird da nichts reingeschrieben. Ein Var-Parameter ist kein Rückgabewert. Anstatt
Delphi-Quellcode:
könntest du auch schreiben:
procedure Test (VAR i: Integer);
Delphi-Quellcode:
VAR bedeutet, dass nicht der Speicherblock, den die Variable belegt, an die Funktion übergeben wird, sondern nur die Startadresse dieses Blocks. Die Funktion kann anhand dieser Adresse in den Speicherblock der Variablen schreiben, und somit kann sich der Wert derr Variablen ändern.
procedure Test (pi: PInteger);
|
Delphi-Quellcode:
zusammen mit
procedure Test (pi: PInteger);
Delphi-Quellcode:
Geht aber auch nicht! Denn IntToStr velangt einen Parameter. Und den kann eine Prozedur nicht liefern.
showmessage (IntToStr (Test (8));
Desshalb müsste die Routine Test schon eine Funktion sein.
Delphi-Quellcode:
function Test (pi: PInteger);
|
@ Hansa
zu deiner Frage: Wieso ist da kein Rückgabewert. Eine Funktion liefert einen Rückgabewert
Delphi-Quellcode:
Diese Funktion hat einen Rückgabewert vom Typ Integer mit dem Wert 5.
function Test : integer;
begin result := 5; end; Eine Prozedur hat keinen Rückgabewert
Delphi-Quellcode:
Diese Prozedur hat keinen Rückgabewert, sondern sie pinselt hier nur den Wert 5 in die Adresse der Variable die du ihr Übergibst.
procedure Test (VAR i : integer);
begin i := 5; end; Deshalb kannst du auch nicht das machen:
Delphi-Quellcode:
Das würde funktionieren:
begin
showmessage (IntToStr (Test (8)); end;
Delphi-Quellcode:
In der Messagebox würde eine 5 stehen.
var i : integer;
begin i := 2; Test (i); showmessage (IntToStr (i); end; Alles klar? mfg Daniel |
Zitat:
|
@Chewie
Weis ich doch, mein Post sollte als Ergänzung zu deinem gesehen werden :D Ich denkmal mittlerweile ist das auch geklärt, oder? |
Zitat:
|
Zitat:
|
Hä? Du hast die 5 nicht als Konstante deklariert :?:
|
Das Argument, daß C++ keine Unterscheidung kennt ist etwas naiv!
C wurde nämlich erfunden um Programmierern das Leben schwer zu machen. Laßt mich mal ein wenig tiefer buddeln: Delphi-Code. Es ist eine Prozedur und eine Funktion! ... STDCALL wurde verwendet um den Unterschied anschaulicher darzustellen, da Delphi ansonsten diverse Parametertypen (u.a. Integer) im Register übergibt.
Delphi-Quellcode:
Etwas Pseudo-Code:
procedure prozedur(var i:Integer); // Anschaulicher!!!
begin i:=i+1; end; function funktion(i:Integer):Integer; stdcall; // Anschaulicher!!! begin result:=i+1; end; procedure TForm1.Button1Click(Sender: TObject); var i:Integer; begin i:=funktion(5); // ergebnis 6 prozedur(i); // ergebnis 7 end;
Code:
Uns interessieren die Stellen zwischen den: "~~~~~~~~~~~~~~".
procedure prozedur(var i:Integer); stdcall;
-------------- push ebp // EBP sichern mov ebp, esp // Stack Frame ~~~~~~~~~~~~~~ mov eax, [ebp+$08] // "EAX := @i" inc dword ptr [eax] // EAX^ := EAX^ + 1 // inc(EAX^) ~~~~~~~~~~~~~~ pop ebp // EBP wiederherstellen ret $04 // Rückkehren -------------- function funktion(i:Integer):Integer; stdcall; -------------- push ebp // EBP sichern mov ebp, esp // Stack Frame ~~~~~~~~~~~~~~ mov eax, [ebp+$08] // EAX := i inc eax // i := i + 1 // inc(i) ~~~~~~~~~~~~~~ pop ebp // EBP wiederherstellen ret $04 // Rückkehren -------------- procedure TForm1.Button1Click(Sender: TObject); -------------- push $05 // Parameterübergabe call 0043C6AC // Funktion Resultat in EAX mov [ebp-$04], eax // i := EAX lea eax, [ebp-$04] // EAX := @i // Adresse von "i" in EAX call 0043C6A8 // Prozedur -------------- Also! Ich habe extra alles kommentiert. Bei Prozedur() sieht man, daß nicht eine lokale Variable auf dem Stack, sondern die Speicheradresse an der "i" liegt, verändert wird. Wenn man so will, wird folgendes übergeben:
Bei Funktion() hingegen wird zuerst der übergebene Wert, welcher auf dem Stack als "lokale Variable" (lokale Variablen und Parameter sind eigentlich intern das Gleiche) liegt, in das Register EAX übergeben. Da ordinale Rückgabewerte bei den Aufrufkonventionen STDCALL und REGISTER jeweils in EAX zurückgegeben werden, wird EAX nur noch inkrementiert. WÜRDE MAN ALSO: Prozedur(i:Integer) schreiben, dann wäre "i" eine "lokale Variable" und damit ginge der Rückgabewert verloren! Hingegen bei obigem Beispiel (als Wieder- holung) wird direkt PInteger(@i)^:=PInteger(@i)^+1; modifiziert. Jetzt klar? Du modifizierst nämlich direkt eine "globale" Variable. Für den Compiler ist das gleich ... der kann jede Speicherstelle so referenzieren, auch wenn im Delphi-Source die Variable "i" innerhalb von Button1Click() eine "lokale" Variable ist. |
Zitat:
Code:
Das ist nicht als CONST deklariert, stimmt, aber trotzdem nicht variabel, außerdem macht es keinen Sinn solch eine Funktion zu verwenden. Es ist halt ein Beispiel.
function Test : integer;
begin result := 5; end; Worauf ich hinaus wollte ist folgendes: Angenommen es muß eine Zahl berechnet werden in einem konkreten Fall, z.B. die Mehrwertsteuer. Wo liegt da hier ein Unterschied ? Zwischen dem hier:
Delphi-Quellcode:
und dem :
procedure MWSTproc (netto : real;var brutto : real);
begin brutto := netto * 1.16; end;
Delphi-Quellcode:
Im Endeffekt wird die Zahl berechnet und basta. Und, wie man sieht ist die eigentliche Berechnung genau dieselbe. Ob das nun im AX Register oder sonstwo gespeichert wird, wen interessiert das ?
function brutto (netto : real) : real;
begin brutto := netto * 1.16; end; In beiden Fällen muß sowieso noch eine globalere Variable deklariert werden, um mit dem berechneten Wert zu hantieren.
Code:
Bei Prozeduren würde das hier den Wert liefern (gespeichert in BruttoVar):
var BruttoVar : real;
Code:
bei Funktionen:
MwstProc (netto,BruttoVar
Code:
Der Nachteil von Funktionen ist halt, daß man nur einen Wert zurück erhält, während man bei Prozeduren mehrere VAR - Parameter übergeben kann. Um beim Beispiel zu bleiben:
BruttoVar := brutto (netto);
Delphi-Quellcode:
Diese Prozedur würde ZWEI Zahlen zurückliefern, die man verwenden könnte !
procedure BerechneBruttoRabatt (netto, rabatt: real; var BruttoOhneRabatt,BruttoMitRabatt : real);
begin BruttoOhneRabatt := netto * 1.16; BruttoMitRabatt := (netto - rabatt) * 1.16; end; @Assarbad: Zitat:
1. kryptische Schreibweise (wegen Steinzeit) 2. Groß- und Kleinschreibung 3. ganz gravierend :!: folgender Code wäre möglich (in Delphi Syntax):
Delphi-Quellcode:
4. usw. :mrgreen:
procedure Test;
begin showmessage (st); VAR st : string; end; |
Hallo Hansa,
Zitat:
Dass Du Deinen Wert wie in Deinem Beispiel sowohl mit einer Prozedur als auch einer Funktion erhalten kannst, daran hat von Anfang an niemand gezweifelt. |
Halte mich eben hier dran :wink: :
Zitat:
Delphi-Quellcode:
und
procedure Test (CONST r : real);
Delphi-Quellcode:
Wie heißt der Vorgänger von Pascal (Wirth) noch ? War es Algol ?
procedure Test (VAR r : real);
|
@Hansa: Jetzt will ich Dich erst einmal bitten nachzudenken ;-) Abgesehen von Deinem ursprünglich gelieferten Beispiel, welches völlig inkorrekt war, hast Du auch weitere Falsch-Aussagen gemacht. Die gravierendste ist jene, die Du immer wieder anbringst:
Zitat:
Delphi-Quellcode:
Also ist dieses Argument schon in einmal nichtig.
function FreeModule(var hLibModule: HINST): BOOL;
function InterlockedIncrement(var Addend: Integer): Integer; stdcall;function GetExitCodeProcess(hProcess: THandle; var lpExitCode: DWORD): BOOL; stdcall; // u.s.w. u.s.f. Ein weiterer Vorteil von Funktionen über Prozeduren ist, deren Rückgabewerte direkt in Berechnungen einbinden zu können. Es besteht nicht der Zwang eine separate Variable zu deklarieren, bevor ich diese nur einmal verwende. Beispiel gefällig? Okay, anhand der Funktionen FileExists und DeleteFile:
Delphi-Quellcode:
Das mal als Beispiel für den Nutzen fon Funktionen. Und das Argument der var-Parameter zieht nicht ;-) Erinnere Dich an den Auszug der Delphi-Grammatik-Regeln. Die geben an, daß die Parameter-Listen Definition für Prozeduren und Funktionen identisch sind. Was in der einen geht, geht auch in der anderen.
// die wohl viel elegantere Lösung via Funktion
// function FileExists(const FileName: string): Boolean; // function DeleteFile(const FileName: string): Boolean; begin if FileExists('C:\Temp\LöschMich.txt') then if not DeleteFile('C:\Temp\LöschMich.txt') then ShowMessage('Die Datei konnte nicht gelöscht werden'); end; // hättest Du es so lieber??? // HYPOTHETISCH // procedure FileExists(const FileName: string; var Result: Boolean); // procedure DeleteFile(const FileName: string; var Success: Boolean); var Status: Boolean; begin FileExists('C:\Temp\LöschMich.txt', Status); if Status then begin DeleteFile('C:\Temp\LöschMich.txt', Status); if not Status then ShowMessage('Die Datei konnte nicht gelöscht werden'); end; end;
Code:
Noch ein weiterer Vortail eine Funktion gegenüber einer Prozedur ist, wenn man nur einen Rückgabewert erwartet, die Geschwindigkeit. Durch die Rückgabe dieses Wertes im (E)AX Register, sind den möglchen Optimierungen durch den Compiler viel mehr Raum gegeben.
[b]Funktionskopf [/b]-> FUNCTION Bezeichner [Formale Parameter] ':' (Einfacher Typ | STRING)
[b]Prozedurkopf [/b]-> PROCEDURE Bezeichner [Formale Parameter] [b]Formale Parameter [/b]-> '(' Formaler Parameter ';'. ')' [b]Formaler Parameter [/b]-> [VAR | CONST | OUT] Parameter [b]Parameter [/b]-> Bezeichnerliste [':' ([ARRAY OF] Einfacher Typ | STRING | DATEI)] -> Bezeichner ':' Einfacher Typ '=' Konstanter Ausdruck Zitat:
Zitat:
Bevor Du jetzt die Diskussion fortsetzt, biite ich Dich, Dir mal den Delphi-Language Guide in die Hand zu nehmen und Dich über die (weiteren) Unterschiede von Prozedure und Funktion zu informieren. ...:cat:... |
ach, wie ist das herrlich. Was liebe ich solche Grundsatzdiskussionen. 8) Könnte fast ein C++ - Forum sein. :mrgreen: Schlimm ist, daß Sakura Recht hat. :lol: Bei Funktionen können auch mehrere VAR Parameter übergeben werden. Und sie können, wie er richtig sagt, direkt für weitere Berechnungen benutzt werden.
Für mich ist letzteres der einzige Grund, Funktionen zu benutzen. Ansonsten ist es mir egal. Compiler-Optimierungen? Da möge mal einer eine Zahl nennen. Wieviel % macht es aus, wenn statt Prozeduren Funktionen oder umgekehrt verwendet werden? |
Zitat:
...:cat:... |
Na also, auch hier hat jeder Recht :lol:, aber eines fehlt noch (insbesondere für Anfänger gefährlich) : Manchmal macht es eher Sinn, einen berechneten Wert in einer Variablen zu speichern, anstatt ihn dauernd neu zu berechnen. Aus Sakuras Millisekunden werden sonst tatsächlich spürbare Wartezeiten. Dies gilt insbesondere für Datenbank-Zugriffe innerhalb einer Funktion.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:56 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz