AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Verhindern, dass eine Funktion zwei mal den gleichen Parameter nutzt
Thema durchsuchen
Ansicht
Themen-Optionen

Verhindern, dass eine Funktion zwei mal den gleichen Parameter nutzt

Ein Thema von Alallart · begonnen am 2. Sep 2025 · letzter Beitrag vom 3. Sep 2025
Antwort Antwort
Alallart

Registriert seit: 8. Dez 2015
173 Beiträge
 
#1

Verhindern, dass eine Funktion zwei mal den gleichen Parameter nutzt

  Alt 2. Sep 2025, 16:45
Ich habe mir zwar nie Gedanken drum gemacht, aber gerade ist mir etwas sonderbares passiert. Ich habe eine Funktion geschrieben, die falsche Werte zurück gibt, wenn man zwei mal den gleichen Parameter nimmt.

Beispiel:

Delphi-Quellcode:
function StrToBase64(Str: string; out Base64Str: string): Byte;
//
Wenn ich das so abrufe:

Delphi-Quellcode:
x := StrToBase64(Result, Result);
//
bekomme ich ein falsches Ergebnis. Eigentlich nichts. Einen leeren String. Intern, also in der Funktion kann ich nichts machen. Die ruft eine Klasse aus einer anderen Unit auf.

Das Problem bekomme ich so leicht gelöst:

Delphi-Quellcode:
x := StrToBase64(Result, s);
Result := s;
Trotzdem, wer weiß ob ich in zwei Jahren die Funktion nutzen werden, und ich habe es vergessen.

Gibt es eine Möglichkeit etwas einzubauen, wo Delphi rebelliert, wenn man zweimal den gleichen Parameter nimmt?
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
10.110 Beiträge
 
Delphi 12 Athens
 
#2

AW: Verhindern, dass eine Funktion zwei mal den gleichen Parameter nutzt

  Alt 2. Sep 2025, 17:05
Das Problem ist, dass ein out-Parameter initialisiert werden muss. Entsprechend wird dort bei der Parameterübergabe ein Leerstring hineingeschrieben.

Das kannst du nur vermeiden, indem du daraus einen var-Parameter machst. Du kannst aber auch ganz einfach den Wert als Rückgabewert liefern und deinen Bytewert als out-Parameter deklarieren.
Sebastian Jänicke
AppCentral
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.710 Beiträge
 
Delphi 12 Athens
 
#3

AW: Verhindern, dass eine Funktion zwei mal den gleichen Parameter nutzt

  Alt 2. Sep 2025, 17:30
Alleine ein VAR anstelle des OUT bringt nicht wirklich eine Veränderung/Lösung.


Jupp, eigentlich würde OUT hier die automatische Speicherverwaltung eines Strings zerschießen,
aber Delphi macht hier heimlich ein VAR aus dem OUT.
Alleine das Erklärt bereits, warum es nichts ändern wird.


Tipp: Wenn du ganz sicher gehn willst,
dann das Ergebnis erst in eine lokale Variable
und ganz zum Schluß ein Result := DeineVariable; .

Oder ganz zu Beginn Str in eine lokale Variable kopieren,
welche aber lange genug existieren muß, was nicht automatisch sichergestellt ist.




Delphi-Quellcode:
function StrToBase64(const Str: string; out Base64Str: string): Byte;
begin
  //if IntPtr(Str) = IntPtr(Base64Str) then
  if (IntPtr(Str) = IntPtr(Base64Str)) and (Str <> '') then
    raise EProgrammerNotFound.Create('du du du 😨');
Man beachte das CONST.

ABER, da du kein CONST angegeben hast, gibt es hier keine Probleme, denn Str ist innerhalb der Funktion quasi eine Kopie.
OK, nicht wirklich, aber die Refferenzzählung ist erhöht, womit beim ersten Schreibzugriff auf Base64Str die Referenzzählung auf 1 gebracht wird, also ab dann sind es zwei unterschiedliche Strings.

Meine Prüfung würde aber "gleich zu Beginn" dennoch einen Fehler werfen, auch wenn er eigenlich unnötig wäre.



PS: MIT CONST gibt es hier erst einen richtigen Fehler, wenn der String vor Funktionsaufruf einen RefCount von 1 hat.

Delphi-Quellcode:
S := 1.ToString;
StrToBase64(S, S);

function StrToBase64(const Str: string; out Base64Str: string): Byte;
begin
  Base64Str := '';
  ShowMessage(Str); // hier kommt '' raus
Delphi-Quellcode:
S := 1.ToString;
StrToBase64(S, S);

function StrToBase64(Str: string; out Base64Str: string): Byte;
begin
  Base64Str := '';
  ShowMessage(Str); // hier kommt '1' raus
Delphi-Quellcode:
S := 1.ToString;
S2 := S;
StrToBase64(S, S);

function StrToBase64({const} Str: string; out Base64Str: string): Byte;
begin
  Base64Str := '';
  ShowMessage(Str); // hier kommt '1' raus, egal ob mit oder ohne const
(hab das jetzt nicht getestet, aber rein logisch müsste es passen)

PS: S := '1'; ist etwas anderes, als ein S := 1.ToString; ,
denn '1' ist eine Konstante (RefCount = -1) und das Andere ergibt wirklich eine Variable (RefCount = +1).


PSS: Genau das ist auch der Grund, bzw. Einer davon, warum in vielen meiner Codes/Komponenten absichtlich oft kein CONST verwendet wird.
(nicht nur, aus Faulheit oder weil der Code dann kürzer und übersichtlicher ist)

Besonders schlimm wird es mit Interfaces bei RefCount=1,
z.B. wenn man ein "Objekt" erstellt und es direkt an einen Interface-Parameter übergibt.
Machwas(TIrgendwas.Create);
Ein Therapeut entspricht 1024 Gigapeut.

Geändert von himitsu ( 2. Sep 2025 um 17:56 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
10.110 Beiträge
 
Delphi 12 Athens
 
#4

AW: Verhindern, dass eine Funktion zwei mal den gleichen Parameter nutzt

  Alt 2. Sep 2025, 18:21
Alleine ein VAR anstelle des OUT bringt nicht wirklich eine Veränderung/Lösung.


Jupp, eigentlich würde OUT hier die automatische Speicherverwaltung eines Strings zerschießen,
aber Delphi macht hier heimlich ein VAR aus dem OUT.
Alleine das Erklärt bereits, warum es nichts ändern wird.
Das stimmt nicht. Das kannst du leicht testen:
Delphi-Quellcode:
function StrToBase64(Str: string; var Base64Str: string): Byte;
begin
  Base64Str := '';
  Base64Str := Str;
end;

procedure Test;
var
  a, b: string;
begin
  a := 'Test';
  StrToBase64(a, a);
  ShowMessage(a);
end;
Mit var kommt da "Test" heraus, mit out ein Leerstring.

// EDIT: Wobei ich nicht sicher bin, ob das Verhalten in der Doku genau genug definiert ist, um sich darauf auch bei zukünftigen Delphiversionen zu verlassen. Ich habe nicht nachgeschaut.

Oder ganz zu Beginn Str in eine lokale Variable kopieren,
welche aber lange genug existieren muß, was nicht automatisch sichergestellt ist.
Das bringt nichts, da Delphi den String dort schon abgeräumt hat, also vor dem begin.

Delphi-Quellcode:
S := 1.ToString;
StrToBase64(S, S);

function StrToBase64(Str: string; out Base64Str: string): Byte;
begin
  Base64Str := '';
  ShowMessage(Str); // hier kommt '1' raus
Delphi-Quellcode:
S := 1.ToString;
S2 := S;
StrToBase64(S, S);

function StrToBase64({const} Str: string; out Base64Str: string): Byte;
begin
  Base64Str := '';
  ShowMessage(Str); // hier kommt '1' raus, egal ob mit oder ohne const
(hab das jetzt nicht getestet, aber rein logisch müsste es passen)
Du solltest es testen. Es stimmt leider nicht.

Den Vergleich hatte ich auch ausprobiert. Da darf nur nicht geprüft werden, ob Str <> '' ist wie in deinem Code, sondern nur der Pointer verglichen werden.
Sebastian Jänicke
AppCentral

Geändert von jaenicke ( 2. Sep 2025 um 18:24 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.710 Beiträge
 
Delphi 12 Athens
 
#5

AW: Verhindern, dass eine Funktion zwei mal den gleichen Parameter nutzt

  Alt 2. Sep 2025, 19:01
ich bin mir sicher ganz viele OUT in Codes gesehen zu haben, also muß es doch funktionieren?
Ein Therapeut entspricht 1024 Gigapeut.

Geändert von himitsu ( 2. Sep 2025 um 19:15 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.710 Beiträge
 
Delphi 12 Athens
 
#6

AW: Verhindern, dass eine Funktion zwei mal den gleichen Parameter nutzt

  Alt 2. Sep 2025, 19:02
Da darf nur nicht geprüft werden, ob Str <> '' ist wie in deinem Code, sondern nur der Pointer verglichen werden.
Wenn es ein Leerstring (nil) ist, dann ist es nicht so schlimm.
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.710 Beiträge
 
Delphi 12 Athens
 
#7

AW: Verhindern, dass eine Funktion zwei mal den gleichen Parameter nutzt

  Alt 2. Sep 2025, 19:11
ich bin mir sicher ganz viele OUT in Codes gesehen zu haben, also muß es doch funktionieren?
Es stimmt leider nicht.
such
such
such
out +[a-z0-9_]+ *: *string

20-30 Mal in unseren Codes (Firma)
und ein paar hunderte Male bei DevExpress, madExcept, JCL, pgDAC, Python4Delphi, uniGUI und Delphi (Cloud, DataSnap, EMS, DBX, FireDAC, REST, DUnit, RTL, ToolsAPI, SOAP, VCL, XML)

hmmmmmmmmmmmmmmmmmmmmmmmm
gefühlt dürfte dann ja fast garnichts mehr funktionieren?

könnte ja nochmal nachsehn/probieren




PS: S := '1'; ist etwas anderes, als ein S := 1.ToString; ,
denn '1' ist eine Konstante (RefCount = -1) und das Andere ergibt wirklich eine Variable (RefCount = +1).
Wie schon erwähnt ... bei "Konstanten" artet die Sache gleich noch mehr aus,
drum hatte ich da vorhin noch garnicht dran denken wollen,
aber stimmt, schon alleine deswegen kann es damit spaßig werden.

Tja, wie schon erwähnt, macht Delphi bei OUT mit gemadagten Typen ein bissl Mist.
(eventuell noch mehr, als gedacht)

Schöner wäre es also, wenn Delphi hier einen Compilerfehler werfen würde, anstatt irgendwie mysteriös dran rumzupfuschen, um die Speicherverwaltung nicht zu beschädigen.
Ein Therapeut entspricht 1024 Gigapeut.

Geändert von himitsu ( 2. Sep 2025 um 19:23 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.710 Beiträge
 
Delphi 12 Athens
 
#8

AW: Verhindern, dass eine Funktion zwei mal den gleichen Parameter nutzt

  Alt 2. Sep 2025, 19:59
Den Vergleich hatte ich auch ausprobiert. Da darf nur nicht geprüft werden, ob Str <> '' ist wie in deinem Code, sondern nur der Pointer verglichen werden.
Der Leerstring ist nicht so schlimm, finde ich, drum diesen Ausschluß,
und bei einem Leerstring kannst du HIER nicht prüfen, ob es die selbe Variable ist, weil beide NIL wären.
Und ob es nun dieselbe Variable mit NIL oder zwei unterschiedliche Variablen mit NIL, kann somit nicht geprüft werden (somit ist es mit diesem Ausschluß besser).
Hierfür müsstest du also die Adressen der Variablen prüfen, anstelle derer Inhalte.

Gehen wir einfach mal auf Nummer sicher:
Delphi-Quellcode:
function StrToBase64(const [Ref] Str: string; out Base64Str: string): Byte; // oder VAR
begin
  if @Str = @Base64Str then
    raise EProgrammerNotFound.Create('du du du 😨');


[ADD]
Ich glaub es ist eh zu umständlich, wenn wir es nachträglich innerhalb der Prozuedur prüfen.
Einfacher/Sicherer wäre es, wenn der Compiler beim Aufruf sowas prüfen und einen Fehler eine Warnung werfen könnte.
(wenn dieselbe Variable in mehrere Parameter reingegebenund wird und mindestens Einer davon ist ein OUT oder VAR)

Geändert von himitsu ( 2. Sep 2025 um 20:17 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.710 Beiträge
 
Delphi 12 Athens
 
#9

AW: Verhindern, dass eine Funktion zwei mal den gleichen Parameter nutzt

  Alt 2. Sep 2025, 20:36
https://embt.atlassian.net/servicede...tal/1/RSS-4013

Code:
// (var i: Integer)  // (out i: Integer)  // (var s: string)  // (out s: string)
lea eax,[ebp-$08]    lea eax,[ebp-$08]    lea eax,[ebp-$0c]   lea eax,[ebp-$0c]
call TestVarInt      call TestOutInt      call TestVarStr     call _UStrClr
                                                              call TestOutStr


// begin             // begin             // begin            // begin
push ebp             push ebp             push ebp            push ebp
mov ebp,esp          mov ebp,esp          mov ebp,esp         mov ebp,esp
push ecx             push ecx             push ecx            push ecx
mov [ebp-$04],eax    mov [ebp-$04],eax    mov [ebp-$04],eax   mov [ebp-$04],eax
                                                              mov eax,[ebp-$04]
                                                              test eax,eax
                                                              jz NEXT
                                                              xor edx,edx
                                                              mov [eax],edx
                                                              NEXT:
// i := 1;           // i := 1;           // s := '1';        // s := '1';
mov eax,[ebp-$04]    mov eax,[ebp-$04]    mov eax,[ebp-$04]   mov eax,[ebp-$04]
mov [eax],$00000001  mov [eax],$00000001  mov edx,$008e9d90   mov edx,$008e9dc4
                                          call _UStrAsg       call _UStrAsg
// end;              // end;              // end;             // end;
pop ecx              pop ecx              pop ecx             pop ecx
pop ebp              pop ebp              pop ebp             pop ebp
ret                  ret                  ret                 ret
Ein Therapeut entspricht 1024 Gigapeut.

Geändert von himitsu ( 2. Sep 2025 um 21:01 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
10.110 Beiträge
 
Delphi 12 Athens
 
#10

AW: Verhindern, dass eine Funktion zwei mal den gleichen Parameter nutzt

  Alt 3. Sep 2025, 05:23
Der Leerstring ist nicht so schlimm, finde ich, drum diesen Ausschluß,
Dann schlägt die Prüfung aber nie an, weil der String an der Stelle immer leer ist. Den Fall nil muss man nicht abfangen, denn der Zielstring kann nie nil sein, oder?
Sebastian Jänicke
AppCentral
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:57 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