Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi Procedure vs Function, Vor- und Nachteile (https://www.delphipraxis.net/196015-procedure-vs-function-vor-und-nachteile.html)

KodeZwerg 15. Apr 2018 12:39

Procedure vs Function, Vor- und Nachteile
 
Hallo, der Titel ist ja recht Aussagekräftig

Beispiele
Delphi-Quellcode:
// Funktionen Vorteil, sie geben etwas direkt wieder
Function Beispiel : Boolean;
begin
  Result := True;
end;

// Proceduren können ja auch etwas wiedergeben per Var
// Nachteil, man benötigt eben eine Variable um das Var auszuwerten
Procedure Beispiel (var bResult: Boolean);
begin
  bResult := True;
end;
Aber was Unterscheidet die Beiden noch? Gibt es im Speicher Unterschiede? Was ist performanter?
Gibt es Unterschiede wie Delphi es handhabt wenn eine Function/Procedure eingeleitet bzw. am Ende angekommen ist?
Oder wie schauts aus in Libraries (DLL), man kann ja beides EXPORT machen.
Was fällt Euch noch zum Thema Procedure vs Function, Vor- und Nachteile ein?
Ich würde gerne Eure Meinungen dazu erfragen, egal wie verwegen, falls es abstrakte Unterschiede gibt.
Oder Beispiele wo man für eine Sache eher das nehmen sollte wohingegen bei anderen Sachen nur das andere genommen werden sollte mit einer Mini-Begründung.

Falls sich jemand hier einklinkt und Antwortet, Danke dafür!

Zacherl 15. Apr 2018 13:00

AW: Procedure vs Function, Vor- und Nachteile
 
Ziemlich wurscht. Wenn man einen Rückgabewert hat, sind Funktionen zu bevorzugen, da sie intuitiver sind und genau für diesen Zweck entwickelt wurden. In seltenen Fällen (bei Übergabe großer Strukturen bzw. Strings, etc.) kann ein
Delphi-Quellcode:
var
Parameter sinnvoll sein, um Kopieroperationen zu vermeiden. Muss man sich im Normalfall aber keine Gedanken drüber machen.

Auf Assembler-Ebene gibt es keine signifikanten Unterschiede.

Redeemer 15. Apr 2018 13:08

AW: Procedure vs Function, Vor- und Nachteile
 
Zitat:

Zitat von Zacherl (Beitrag 1399294)
Ziemlich wurscht. Wenn man einen Rückgabewert hat, sind Funktionen zu bevorzugen, da sie intuitiver sind und genau für diesen Zweck entwickelt wurden. In seltenen Fällen (bei Übergabe großer Strukturen bzw. Strings, etc.) kann ein
Delphi-Quellcode:
var
Parameter sinnvoll sein, um Kopieroperationen zu vermeiden. Muss man sich im Normalfall aber keine Gedanken drüber machen.

Da hast du
Delphi-Quellcode:
var
mit
Delphi-Quellcode:
const
verwechselt.

Zudem verwechselt ihr beide
Delphi-Quellcode:
var
mit
Delphi-Quellcode:
out
.

KodeZwerg 15. Apr 2018 13:16

AW: Procedure vs Function, Vor- und Nachteile
 
Da würde ich gerne nochmal nachhaken
Delphi-Quellcode:
Procedure Beispiel1 (var bResult: Boolean);
begin
  bResult := True;
end;

Procedure Beispiel2 (out bResult: Boolean);
begin
  bResult := True;
end;
Was Unterscheidet Beispiel1 von Beispiel2? Beides schreibt doch bResult um?

günni0 15. Apr 2018 13:18

AW: Procedure vs Function, Vor- und Nachteile
 
Vielleicht hilft das hier
https://www.delphipraxis.net/39878-w...parameter.html

KodeZwerg 15. Apr 2018 13:25

AW: Procedure vs Function, Vor- und Nachteile
 
Zitat:

OUT ist grundsätzlich (per Definition) wie das Funktions-RESULT.
"Wenn" etwas rein geht, dann wird es ignoriert und es wird nur etwas zurückgegeben.
Bzw. der Programmierer darf niemals davon ausgehen, dass dort "gültige" Were von außen rein kommen.

Der Compiler behandelt es allerdings vorallem wie VAR, nur sollte er zumindestens die "Variable nicht initialisiert"-Prüfung deaktivieren.
Hat geholfen, Danke!

edit
Zitat:

Zitat von Zacherl (Beitrag 1399294)
Auf Assembler-Ebene gibt es keine signifikanten Unterschiede.

Dafür auch Danke!

himitsu 15. Apr 2018 13:31

AW: Procedure vs Function, Vor- und Nachteile
 
Zitat:

Zitat von Zacherl (Beitrag 1399294)
In seltenen Fällen (bei Übergabe großer Strukturen bzw. Strings, etc.) kann ein
Delphi-Quellcode:
var
Parameter sinnvoll sein, um Kopieroperationen zu vermeiden. Muss man sich im Normalfall aber keine Gedanken drüber machen.

Gerade da ist es total wurscht,
denn bei gemanagten Typen ala String, Variant, Interface und dynamischen Arrays macht der Delphi-Compiler aus
Delphi-Quellcode:
function Beispiel(...): string;
eben auch ein
Delphi-Quellcode:
procedure Beispiel(...; var Result: string);
und kopiert nichts um.

Leider ist das auch das Problem/die Urache, dass bei Funktionen für das Result keine "wurde nicht initialisiert"-Meldung vom Compiler kommt, da es eben doch initialisiert wurde (außerhalb)
und mit dem Ergebnis, dass bei vergessenen Initialisierung schnell etwas Komisches heraus kommt,
Delphi-Quellcode:
function Test: string;
begin
  Result := Result + 'a';
end;

for i := 1 to 5 do
  S := Test;
ShowMessage(S); // 'aaaaa'
aber wenn man sich das jetzt gedanklich als Prozedur ansieht, dann ist sofort klar, warum es so ist.

günni0 15. Apr 2018 13:41

AW: Procedure vs Function, Vor- und Nachteile
 
Zitat:

Delphi-Quellcode:
function Test: string;
begin
  Result := Result + 'a';
end;

for i := 1 to 5 do
  S := Test;
ShowMessage(S); // 'aaaaa'

Ich stehe gerade etwas auf dem Schlauch. Aber warum wird aaaaa ausgegeben?
Man schreibt S bei jedem Schleifendurchlauf doch neu und pro "Test" wird nur 1x a hinzugefügt.

Sollte das nicht nur "a" angezeigt werden?

KodeZwerg 15. Apr 2018 13:47

AW: Procedure vs Function, Vor- und Nachteile
 
Zitat:

Zitat von günni0 (Beitrag 1399300)
Zitat:

Delphi-Quellcode:
function Test: string;
begin
  Result := Result + 'a';
end;

for i := 1 to 5 do
  S := Test;
ShowMessage(S); // 'aaaaa'

Ich stehe gerade etwas auf dem Schlauch. Aber warum wird aaaaa ausgegeben?
Man schreibt S bei jedem Schleifendurchlauf doch neu und pro "Test" wird nur 1x a hinzugefügt.

Sollte das nicht nur "a" angezeigt werden?

Nein, S wird 5x durch function addiert (Result := Result + 'a';)

günni0 15. Apr 2018 13:59

AW: Procedure vs Function, Vor- und Nachteile
 
Aber Test() hat doch keinerlei Parameter. Wie kommt diese Prozedur denn an die vorherigen Zuweisungen?

Ghostwalker 15. Apr 2018 14:08

AW: Procedure vs Function, Vor- und Nachteile
 
Weil der Programmierer bewußt die Compiler-Warnung "Result wurde nicht initialisizert !" ignoriert. Somit behält result u.U. seinen Wert und es wird dazu ein 'a' addiert.

günni0 15. Apr 2018 14:12

AW: Procedure vs Function, Vor- und Nachteile
 
Boing... jetzt habs ich kapiert. Also ein klassischer Fehler.

himitsu 15. Apr 2018 14:18

AW: Procedure vs Function, Vor- und Nachteile
 
Wie gesagt, der Compiler macht aus solchen Funktionen eben eine Prozedur mit VAR-Parameter
Delphi-Quellcode:
procedure Test(var Result: string); //function Test: string;
begin
  Result := Result + 'a';
end;

for i := 1 to 5 do
  Test(S); //S := Test;
ShowMessage(S); // 'aaaaa'
Grundsätzlich ist das für den Entwickler egal.
Er muß eben nur selber aufpassen, dass er solche Variablen initialisiert. Am Enfachsten grundsätzlich immer alle Result-Variablen selber initialisieren, wenn mit dem Startwert gerechnet wird.
Für den Compiler ist es so halt viel anfacher die Result-Variable zu verwalten, denn bei gemanagten Typen muß er selber dafür sorgen, dass letztendlich diese Variable immer ordnungsgemäß freigegeben werden und das ist hier einfacher, wenn er direkt die äußere Variable nimmt.

KodeZwerg 15. Apr 2018 14:28

AW: Procedure vs Function, Vor- und Nachteile
 
Zitat:

Zitat von Ghostwalker (Beitrag 1399309)
Compiler-Warnung "Result wurde nicht initialisizert !"

Erscheint bei mir nicht, Warnungen (0), Fehler (0)
Muss ich irgendwo was ändern das der eine Warnung wirft bzw hab ich irgendwo was abgeschaltet was das verhindert?

edit
Delphi-Quellcode:
function Test1: string;
begin Result := Result + 'a'; end;

function Test2: string;
begin Result := 'a' + Result; end;

procedure TForm1.Button1Click(Sender: TObject);
var i : Byte; S : String;
begin
  for i := 1 to 5 do S := Test1;
  Label1.Caption := S;
end;

procedure TForm1.Button2Click(Sender: TObject);
var i : Byte; S : String;
begin
  for i := 1 to 5 do S := Test2;
  Label2.Caption := S;
end;
So ist's in meinem Delphi ohne Warnungen/Fehler kompiliert worden.

himitsu 15. Apr 2018 14:55

AW: Procedure vs Function, Vor- und Nachteile
 
Zitat:

Zitat von KodeZwerg (Beitrag 1399314)
Zitat:

Zitat von Ghostwalker (Beitrag 1399309)
Compiler-Warnung "Result wurde nicht initialisizert !"

Erscheint bei mir nicht, Warnungen (0), Fehler (0)
Muss ich irgendwo was ändern das der eine Warnung wirft bzw hab ich irgendwo was abgeschaltet was das verhindert?

Lesen?

https://www.delphipraxis.net/1399299-post7.html

Delphi.Narium 15. Apr 2018 15:03

AW: Procedure vs Function, Vor- und Nachteile
 
Bei Delphi 7 kann man in den Projektoptionen unter Compilermeldungen auswählen, ob die Warnung 'Dr Rückgabewert der Funktion könnte undefiniert sein.' ausgegeben werden soll oder nicht.

Sieht bei den Meldungen dann sinngemäß so aus:
Code:
[Warnung] Unit1.pas(Zeile): Rückgabewert der Funktion 'TForm1.NameDerFunktion' könnte undefiniert sein

KodeZwerg 15. Apr 2018 15:07

AW: Procedure vs Function, Vor- und Nachteile
 
@himitsu: Ja schon, Du schreibst werden nicht Angezeigt, Ghostwalker schreibt das der Programmierer diese Warnung ignoriert.
Wenn er also eine Angezeigt bekommt, das hätte ich auch gerne, weshalb ich da nochmal nachhakte.

Redeemer 15. Apr 2018 15:22

AW: Procedure vs Function, Vor- und Nachteile
 
Zitat:

Zitat von Delphi.Narium (Beitrag 1399318)
Bei Delphi 7 kann man in den Projektoptionen unter Compilermeldungen auswählen, ob die Warnung 'Dr Rückgabewert der Funktion könnte undefiniert sein.' ausgegeben werden soll oder nicht.

Sieht bei den Meldungen dann sinngemäß so aus:
Code:
[Warnung] Unit1.pas(Zeile): Rückgabewert der Funktion 'TForm1.NameDerFunktion' könnte undefiniert sein

Darum geht es nicht. Es geht darum, in der Funktion die Ergebnisvariable zu lesen bevor sie geschrieben wurde:
Delphi-Quellcode:
function Test: string;
begin
  Result := Result + 'a';
end;
Es geht aber noch schlimmer:
Delphi-Quellcode:
function Test: Integer;
begin
  Result := Result + 1;
end;

begin
  ShowMessage(IntToStr(Test));
end;
Niemand wird dir sagen können, was dieses Programm tut.

Delphi.Narium 15. Apr 2018 15:33

AW: Procedure vs Function, Vor- und Nachteile
 
Doch, es geht u. a. um die entsprechende Warnung:

Ghostwalker schrieb hier: https://www.delphipraxis.net/1399309-post11.html, dass es sie gibt.

Und Kodezwerg schrieb dort: https://www.delphipraxis.net/1399314-post14.html, dass er die Meldung nicht erhalte und fragte nach, was er machen/ändern müsse, um diese Warnung zu erhalten.

Darauf bezog ich mich und nicht darauf, dass das zur Diskussion stehende Codefragment nicht zwingend klar und verständlich ist, sondern nur als Beispiel für den Unterschied zwischen Prozeduren und Funktionen und ggfls. daraus resultierenden Fallstricken dient.

Ghostwalker 15. Apr 2018 15:45

AW: Procedure vs Function, Vor- und Nachteile
 
Zitat:

Zitat von Redeemer (Beitrag 1399320)
[DELPHI]
Es geht aber noch schlimmer:
Delphi-Quellcode:
function Test: Integer;
begin
  Result := Result + 1;
end;

begin
  ShowMessage(IntToStr(Test));
end;
Niemand wird dir sagen können, was dieses Programm tut.

Doch...es addiert 1 zu einem zufälligen Wert, der zu diesem Zeitpunkt an der Speicherstelle steht.
Und diesen Wert zeigt das Programm dir dann an.

Aber das ganze kann natürlich auch bei komplizierteren Funktionen durchaus noch ganz andere Effekte haben. Genau deswegen gibts die Warnung.


Mit Ignorieren war schlicht gemeint, das die entsprechende Warnung ausgeschalten war, oder die Warnung vom Programmierer bewußt nicht gelesen wurde. :)

himitsu 15. Apr 2018 16:14

AW: Procedure vs Function, Vor- und Nachteile
 
Delphi-Quellcode:
function Test: Integer;
begin
  Result := Result + 1;
end;
Delphi-Quellcode:
function Test: string; // procedure Test(var Result: string);
begin
  Result := Result + 'a';
end;
Genau das sagte ich doch.
Bei Ersten kommt die Fehlermeldung, da der Integer wirklich als lokale Variable existiert, als Result in EAX zurückgeliefert und anschließend der äußeren Variable zugewiesen wird.
Während beim String (vom Compiler speicherverwalteter Zeigertyp) keine lokale Variable existiert und direkt in den referenzierten Parameter geschrieben wird.

Delphi-Quellcode:
function Test: Integer;
begin
  Result := Result + 1;
  raise Exception.Create('');
end;

i := 123;
try
  i := Test;
except
end;
ShowMessage(i.toString); // immer 123
Delphi-Quellcode:
function Test: string; // procedure Test(var Result: string);
begin
  Result := Result + 'a';
  raise Exception.Create('');
end;

s := 'x';
try
  s := Test;
except
end;
ShowMessage(S); // je nach Compileroptiomierung auch mal 'xa' und nicht 'x'
Hängt davon ab, ob der Compiler für das Result automatisch eine lokale Variable erstellt und anschließend umkopiert oder direkt das Result nimmt.
Delphi-Quellcode:
s := 'x';
try
  Test(temp); // temp := Test;
  s := temp;
except
end;

// oder

s := 'x';
try
  Test(s); // s := Test;
except
end;
In einer Schleife mehrfach Test aufgerufen bekommt die Funktion aber praktisch immer wieder die selbe Variable rein.

KodeZwerg 15. Apr 2018 17:11

AW: Procedure vs Function, Vor- und Nachteile
 
Zitat:

Zitat von Delphi.Narium (Beitrag 1399318)
in den Projektoptionen unter Compilermeldungen auswählen, ob die Warnung 'Dr Rückgabewert der Funktion könnte undefiniert sein.'

Verzeih das ich jetzt erst darauf reagiere, Mittagessen, Füße hoch und so :)
Danke für den Tipp, ich habe auch probiert Ihn umzusetzen, nun hab ich alle Meldungen On/Off durch mit dem Resultat wie himitsu schrieb, es gibt keine Warnung für das
Delphi-Quellcode:
procedure Test(var Result: string); begin Result := Result + 'a'; end;
Beispiel.
Dennoch Danke! Auch nochmal an himitsu für die vielen Beispiele und Erklärungen!

Zacherl 15. Apr 2018 18:22

AW: Procedure vs Function, Vor- und Nachteile
 
Zitat:

Zitat von Redeemer (Beitrag 1399295)
Zitat:

Zitat von Zacherl (Beitrag 1399294)
Ziemlich wurscht. Wenn man einen Rückgabewert hat, sind Funktionen zu bevorzugen, da sie intuitiver sind und genau für diesen Zweck entwickelt wurden. In seltenen Fällen (bei Übergabe großer Strukturen bzw. Strings, etc.) kann ein
Delphi-Quellcode:
var
Parameter sinnvoll sein, um Kopieroperationen zu vermeiden. Muss man sich im Normalfall aber keine Gedanken drüber machen.

Da hast du
Delphi-Quellcode:
var
mit
Delphi-Quellcode:
const
verwechselt.

Delphi-Quellcode:
var
ist genau wie (meistens)
Delphi-Quellcode:
const
ein "pass by reference", also stimmt das schon mit der Vermeidung von unnötigen Kopieroperationen. Da ein Output Parameter ja aber gewünscht ist, macht
Delphi-Quellcode:
const
hier keinen Sinn :gruebel:

Zitat:

Zitat von Redeemer (Beitrag 1399295)
Zudem verwechselt ihr beide
Delphi-Quellcode:
var
mit
Delphi-Quellcode:
out
.

Nöö.
Delphi-Quellcode:
var
ist runtergebrochen auf den generierten Code exakt gleichwertig zu
Delphi-Quellcode:
out
(auch wenn out gegebenenfalls aus Gründen der Übersichtlichkeit zu bevorzugen ist).

Code:
005CE2D4 E8BFFFFFFF      call Beispiel1 // function
Unit2.pas.48: Beispiel2(X);
005CE2D9 8D45FB          lea eax,[ebp-$05]
005CE2DC E8C7FFFFFF      call Beispiel2 // procedure mit var
Unit2.pas.49: Beispiel3(X);
005CE2E1 8D45FB          lea eax,[ebp-$05]
005CE2E4 E8CFFFFFFF      call Beispiel3 // procedure mit out
Zitat:

Zitat von himitsu (Beitrag 1399299)
bei gemanagten Typen ala String, Variant, Interface und dynamischen Arrays macht der Delphi-Compiler aus
Delphi-Quellcode:
function Beispiel(...): string;
eben auch ein
Delphi-Quellcode:
procedure Beispiel(...; var Result: string);
und kopiert nichts um

Interessant. So viel "Intelligenz" hätte ich dem Delphi Compiler ernsthaft nicht zugetraut. Wieder was gelernt.

himitsu 15. Apr 2018 19:07

AW: Procedure vs Function, Vor- und Nachteile
 
Prozedur für Füllen von Objekten ala Listen, wo es als Result oft ungünstig ist.

Und Prozedur hat eher Nachteile, denn du brauchst da immer eine "selbstdefinierte" Variable und man kann es nicht direkt weitergeben, z.B. als Parameter an eine andere Prozedur/Funktion oder für's Zusammenrechnen mehrerer Werte ohne Zwischenvariablen.

himitsu 15. Apr 2018 19:09

AW: Procedure vs Function, Vor- und Nachteile
 
VAR und OUT ist praktisch das Gleiche, außer dass bei OUT per Definition kein Eingabewert existiert, also die Variable initialisiert werden müsste, aber für Typen ala String/Array/Interface bricht der Compiler dieses, da sonst die ordnungsgemäße Speicherverwaltung nicht mehr garantiert werden kann.

KodeZwerg 15. Apr 2018 19:55

AW: Procedure vs Function, Vor- und Nachteile
 
und das man bei OUT innerhalb der procedure/function nicht lesend darauf zugreifen sollte, so hab ich das verstanden, richtig?

himitsu 15. Apr 2018 20:16

AW: Procedure vs Function, Vor- und Nachteile
 
Man darf, vor allem nachdem man schon etwas zugewiesen hat.

Vor der ersten Zuweisung ist der Wert einfach "undefiniert", so wie bei lokalen Variablen (Integer und so).

KodeZwerg 15. Apr 2018 20:22

AW: Procedure vs Function, Vor- und Nachteile
 
Danke, ich habe das mit VAR und OUT nun dank Euch/Dir verinnerlicht! Super Forum & Super Community, ich freue mich hier sein zu dürfen.

Ghostwalker 16. Apr 2018 05:47

AW: Procedure vs Function, Vor- und Nachteile
 
Das die Warnung bei gemanagten Datentypen garnicht erscheint ist mir ehrlich gesagt bisher nicht aufgefallen:oops:.

Das mit var und out war mir bisher auch nicht bewußt, da ich in der Regel bei solchen Fällen
immer var benutzt habe. Man lernt nie aus :)

In den letzten Versionen scheint sich da auch (positiv) am Compiler doch einiges geändert zu haben, denn
selbst in folgendem Fall, erkennt der Compiler, das result nicht undefiniert sein kann (war schonmal anders :)).

Delphi-Quellcode:
function Test(wupti:boolean):integer;
begin
  if (wupti) then
    result := 1
  else
    result := 0;
end;

bernau 16. Apr 2018 08:28

AW: Procedure vs Function, Vor- und Nachteile
 
Zitat:

Zitat von himitsu (Beitrag 1399299)
Zitat:

Zitat von Zacherl (Beitrag 1399294)
In seltenen Fällen (bei Übergabe großer Strukturen bzw. Strings, etc.) kann ein
Delphi-Quellcode:
var
Parameter sinnvoll sein, um Kopieroperationen zu vermeiden. Muss man sich im Normalfall aber keine Gedanken drüber machen.

Gerade da ist es total wurscht,
denn bei gemanagten Typen ala String, Variant, Interface und dynamischen Arrays macht der Delphi-Compiler aus
Delphi-Quellcode:
function Beispiel(...): string;
eben auch ein
Delphi-Quellcode:
procedure Beispiel(...; var Result: string);
und kopiert nichts um.

Leider ist das auch das Problem/die Urache, dass bei Funktionen für das Result keine "wurde nicht initialisiert"-Meldung vom Compiler kommt, da es eben doch initialisiert wurde (außerhalb)
und mit dem Ergebnis, dass bei vergessenen Initialisierung schnell etwas Komisches heraus kommt,
Delphi-Quellcode:
function Test: string;
begin
  Result := Result + 'a';
end;

for i := 1 to 5 do
  S := Test;
ShowMessage(S); // 'aaaaa'
aber wenn man sich das jetzt gedanklich als Prozedur ansieht, dann ist sofort klar, warum es so ist.

Damit würde ich aber schlaflose Nächte haben.

Result ist definitiv nicht initialisiert und besitzt einen Zufallswert, der ggf. dann von dem vorherigen Funktionsaufruf noch zufällig vorhanden ist.

Mag sein, dass das jetzt so funktioniert. Dieses Verhalten ist aber nirgends dokumentiert. (Oder ich habe es noch nicht gesehen.)

Bei einer nächsten Compilerfunktion wird das ggf. ganz anders sein.

p80286 16. Apr 2018 09:36

AW: Procedure vs Function, Vor- und Nachteile
 
Interessantes Beispiel was Himitsu da gepostet hat
Delphi-Quellcode:
function Test: string;
begin
   Result := Result + 'a';
end;

for i := 1 to 5 do
   S := Test;
 ShowMessage(S); // 'aaaaa'
nicht nur, das ich ein seltsames Ergebnis bei einer fehlenden Initialisierung bekomme, nein, mein Virenscanner hat auch einen Trojaner gefunden:

Zitat:

Fuery.A!Cl

Kategorie: Trojaner

Beschreibung: Dieses Programm ist gefährlich. Es führt Befehle eines Angreifers aus.

Empfohlene Aktion: Entfernen Sie diese Software unverzüglich.

Elemente:
file:C:\compiler\borland\delphi7\Projects\Project1 .exe
process:pid:1048,ProcessStart:131683403956390456


Gruß
K-H

himitsu 16. Apr 2018 10:28

AW: Procedure vs Function, Vor- und Nachteile
 
Zitat:

Zitat von p80286 (Beitrag 1399360)
nein, mein Virenscanner hat auch einen Trojaner gefunden:

Das liegt aber nur sekundär an diesem Code.
Dein altes Delphi 7 und dass zuviele böse Programme in Delphi geschrieben wurden und weil viele Virensignaturen einfach nur Schrott sind.

https://www.virustotal.com/de/ zur Gegenprobe

Und die eigene Software kann man als False-Positive melden, dann wird die Signatur meist recht schnell angepasst.
https://www.microsoft.com/en-us/wdsi/filesubmission

Amateurprofi 16. Apr 2018 11:41

AW: Procedure vs Function, Vor- und Nachteile
 
Zitat:

Zitat von bernau (Beitrag 1399351)
Zitat:

Zitat von himitsu (Beitrag 1399299)
Zitat:

Zitat von Zacherl (Beitrag 1399294)
In seltenen Fällen (bei Übergabe großer Strukturen bzw. Strings, etc.) kann ein
Delphi-Quellcode:
var
Parameter sinnvoll sein, um Kopieroperationen zu vermeiden. Muss man sich im Normalfall aber keine Gedanken drüber machen.

Gerade da ist es total wurscht,
denn bei gemanagten Typen ala String, Variant, Interface und dynamischen Arrays macht der Delphi-Compiler aus
Delphi-Quellcode:
function Beispiel(...): string;
eben auch ein
Delphi-Quellcode:
procedure Beispiel(...; var Result: string);
und kopiert nichts um.

Leider ist das auch das Problem/die Urache, dass bei Funktionen für das Result keine "wurde nicht initialisiert"-Meldung vom Compiler kommt, da es eben doch initialisiert wurde (außerhalb)
und mit dem Ergebnis, dass bei vergessenen Initialisierung schnell etwas Komisches heraus kommt,
Delphi-Quellcode:
function Test: string;
begin
  Result := Result + 'a';
end;

for i := 1 to 5 do
  S := Test;
ShowMessage(S); // 'aaaaa'
aber wenn man sich das jetzt gedanklich als Prozedur ansieht, dann ist sofort klar, warum es so ist.

Damit würde ich aber schlaflose Nächte haben.

Result ist definitiv nicht initialisiert und besitzt einen Zufallswert, der ggf. dann von dem vorherigen Funktionsaufruf noch zufällig vorhanden ist.

Mag sein, dass das jetzt so funktioniert. Dieses Verhalten ist aber nirgends dokumentiert. (Oder ich habe es noch nicht gesehen.)

Bei einer nächsten Compilerfunktion wird das ggf. ganz anders sein.

Doch, Result ist definitiv initialisiert und besitzt keinen Zufallswert.
Bei "Function Test:String;" ist Result ein Zeiger auf eine Stringvariable und da Strings immer initialisiert werden, ist damit auch Result initialisiert.
Im nachstehenden Assembler-Auszug kannst du das schön sehen.
Vor dem Aufruf der Funktion Test wird mit lea eax,[ebp-$04] die Adresse der lokalen Variablen S in EAX gestellt.
Das in [ebp-4] tatsächlich die Variable S gespeichert ist, siehst du 6 Zeilen tiefer, wo S als Parameter für ShowMessage in EAX gestellt wird.
Recht hättest du bei z.B. Function Test:Integer;, da ist Result nicht initialisiert.

C_Main.pas.5152: for I:=1 to 5 do
0060FFF4 BB05000000 mov ebx,$00000005
C_Main.pas.5153: S:=Test;
0060FFF9 8D45FC lea eax,[ebp-$04]
0060FFFC E8B7FFFFFF call Test
C_Main.pas.5152: for I:=1 to 5 do
00610001 4B dec ebx
00610002 75F5 jnz $0060fff9
C_Main.pas.5154: ShowMessage(S);
00610004 8B45FC mov eax,[ebp-$04]
00610007 E8C0A2ECFF call ShowMessage

Zacherl 16. Apr 2018 12:21

AW: Procedure vs Function, Vor- und Nachteile
 
Unintuitiv ist das Verhalten allerdings schon. Bei einer Funktion in Delphi erwarte ich grundsätzlich temporäre R-Values. Andere Sprachen - wie z.b. C++ - erlauben ja auch die Rückgabe von Referenzen, da ist das Verhalten aber einheitlich.

himitsu 16. Apr 2018 12:27

AW: Procedure vs Function, Vor- und Nachteile
 
Zitat:

Doch, Result ist definitiv initialisiert und besitzt keinen Zufallswert.
Bei "Function Test:String;" ist Result ein Zeiger auf eine Stringvariable und da Strings immer initialisiert werden, ist damit auch Result initialisiert.
Bitte meine Beiträge dazu genau lesen.

Ja, es wird initialisiert, aber eben nicht dort, wo man vermuten könnte (zu Beginn der Funktion),
also ist aus Sicht der Funktion dieses Result eben nicht "wirklich" initialisiert, zumindestens nicht unbeding mit 0 (einem Leerstring).

Amateurprofi 16. Apr 2018 12:42

AW: Procedure vs Function, Vor- und Nachteile
 
Zitat:

Zitat von himitsu (Beitrag 1399374)
Zitat:

Doch, Result ist definitiv initialisiert und besitzt keinen Zufallswert.
Bei "Function Test:String;" ist Result ein Zeiger auf eine Stringvariable und da Strings immer initialisiert werden, ist damit auch Result initialisiert.
Bitte meine Beiträge dazu genau lesen.

Ja, es wird initialisiert, aber eben nicht dort, wo man vermuten könnte (zu Beginn der Funktion),
also ist aus Sicht der Funktion dieses Result eben nicht "wirklich" initialisiert, zumindestens nicht unbeding mit 0 (einem Leerstring).

Sehe ich anders.
Es ist ein grundsätzliches Konzept von Delphi, dass Strings IMMER initialisiert werden, was ja auch eine Voraussetzung für die Referenzzählung ist.
Somit kann es keinen nicht-initialisierten String geben, und auch aus Sicht der Funktion gilt, dass der String (wie auch immer) initialisiert ist und einen gültigen Inhalt hat.
Anders wäre es zum Beispiel bei einem Double - da kann auch was ungültiges drin sein.
Recht hast du natürlich damit, dass die Funktion nicht davon ausgehen kann, dass Result bei Aufruf der Funktion leer ist.

Zacherl 16. Apr 2018 14:19

AW: Procedure vs Function, Vor- und Nachteile
 
Zitat:

Zitat von Amateurprofi (Beitrag 1399375)
Sehe ich anders.
Es ist ein grundsätzliches Konzept von Delphi, dass Strings IMMER initialisiert werden, was ja auch eine Voraussetzung für die Referenzzählung ist.
Somit kann es keinen nicht-initialisierten String geben, und auch aus Sicht der Funktion gilt, dass der String (wie auch immer) initialisiert ist und einen gültigen Inhalt hat.

Selbst bei den
Delphi-Quellcode:
class operator
werden temporäre R-Values verwendet. Wenn man beispielsweise die Addition eines Record überläd, wird ein komplett neuer temporärer Record erstellt und als Ergebnis des Operators zurückgeliefert, welcher dann letztlich der L-Value zugewiesen wird (was meiner Meinung nach schon ziemlicher Schwachsinn ist, aber okay ...). Dadurch dass der String intern als
Delphi-Quellcode:
var
Parameter übergeben wird, spart Delphi sich natürlich die unnötige Kopiererei, wird dadurch an dieser Stelle aber extrem inkonsequent. Das erwartete Verhalten wäre, dass beim Betreten der Funktion eine neue lokale String Instanz (
Delphi-Quellcode:
Result
) mit einem leeren String initialisiert wird. Auf dieser Instanz kann man dann lokal arbeiten und nach Rückkehr der Funktion wird der Wert dann der entsprechenden left-hand-side zugewiesen. Wäre sicherlich etwas komplizierter die Referenzzählung über Funktionsgrenzen hinweg zu gestalten (Delphi räumt lokale Objekte ja vor dem Verlassen der Funktion frei), aber ist keineswegs ein Ding der Unmöglichkeit. Die hier momentan Verwendete Optimierung ist ein reiner Hack.

himitsu 16. Apr 2018 14:30

AW: Procedure vs Function, Vor- und Nachteile
 
Zitat:

Zitat von Zacherl (Beitrag 1399380)
Selbst bei den class operator werden temporäre R-Values verwendet. Wenn man beispielsweise die Addition eines Record überläd, wird ein komplett neuer temporärer Record erstellt und als Ergebnis des Operators zurückgeliefert, welcher dann letztlich der

Was aber eventuell nichts mit diesem Problem zu tun hat,
denn wenn dort dieser Result-Record auch als VAR-Parameter in eine neue leere Variable geht, dann wäre es praktisch das Gleiche.

bernau 16. Apr 2018 15:00

AW: Procedure vs Function, Vor- und Nachteile
 
Zitat:

Zitat von Amateurprofi (Beitrag 1399370)
Doch, Result ist definitiv initialisiert und besitzt keinen Zufallswert.

Mag sein, dass beim ersten Aufruf von "Test" das Result mit "" initialisiert ist.

Wenn Result bei jedem Aufruf von "Test" initialisiert wäre, dann würde als Ergebnis immer "a" herhauskommen. Ist aber nicht so. Es ist immer der Wert des vorherigen Result vorhanden. Was für mich erst mal undefiniert ist.

Da man ja nicht weis, von wo überall "Test" aufgerufen wird, muss man davon ausgehen, dass Result einen string mit dem Buchstaben "a" in zufälliger Länge hat. Was übrigens irgendwann einen Stackoverflow nach sich zieht, wenn "Test" nur oft genug ausgeführt wird.

Zusätzlich kommt hinzu, dass das Verhalten sich mit dem nächsten Compiler ändern kann. Dann wird vielleicht Result bei jedem Aufruf der Funktion auf "" gesetzt. Mann weis ja nie. Es sei denn, dass dieses Verhalten so dokumentiert ist.

Zacherl 16. Apr 2018 15:04

AW: Procedure vs Function, Vor- und Nachteile
 
Zitat:

Zitat von himitsu (Beitrag 1399384)
Zitat:

Zitat von Zacherl (Beitrag 1399380)
Selbst bei den class operator werden temporäre R-Values verwendet. Wenn man beispielsweise die Addition eines Record überläd, wird ein komplett neuer temporärer Record erstellt und als Ergebnis des Operators zurückgeliefert, welcher dann letztlich der

Was aber eventuell nichts mit diesem Problem zu tun hat,
denn wenn dort dieser Result-Record auch als VAR-Parameter in eine neue leere Variable geht, dann wäre es praktisch das Gleiche.

Damit wollte ich vor allem die Inkonsistenz aufzeigen.

Zitat:

Zitat von bernau (Beitrag 1399387)
Was übrigens irgendwann einen Stackoverflow nach sich zieht, wenn "Test" nur oft genug ausgeführt wird.

Nee, das nicht. Strings werden in Delphi Heap-allocated.

Zitat:

Zitat von bernau (Beitrag 1399387)
Zusätzlich kommt hinzu, dass das Verhalten sich mit dem nächsten Compiler ändern kann. Dann wird vielleicht Result bei jedem Aufruf der Funktion auf "" gesetzt. Mann weis ja nie. Es sei denn, dass dieses Verhalten so dokumentiert ist.

Das ist ein wichtiger Punkt. Bin auch der Meinung, dass zumindest die "nicht initialisiert" Meldung trotzdem angezeigt oder die ganze Optimierung anders umgesetzt werden sollte.


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:47 Uhr.
Seite 1 von 3  1 23      

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