Autor Beitrag
Tranx
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 648
Erhaltene Danke: 85

WIN 2000, WIN XP
D5 Prof
BeitragVerfasst: Mo 28.01.13 07:34 
Hallo, ich habe (Delphi 5) einen folgenden Prozedur definiert:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
  procedure Procname(a : string; b : string = ''; c : integer = 10);
  begin
  :
    if c<10 then
      TueIrgendwas
    else
      TueWasAnderes;  
  :
  end;


Wenn ich nun den Aufruf Procname('Test') mache, dann bekomme ich zwar a als 'Test', b als '' aber c nicht unbedingt als 10 übergeben. Manchmal steht da 0, dann -1 in c. Dann ist eine Abfrage innerhalb der Prozedur nicht möglich, denn das Ergebnis ist nicht eindeutig (siehe Teil der Prozedur)

Wenn ich die Funktion so definiere:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
  procedure Procname(a : string; c : integer = 10);
  begin
  :
    if c<10 then
      TueIrgendwas
    else
      TueWasAnderes;  
  :
  end;


Dann hat c immer 10, wenn ich nur den Aufruf Procname('Test') wähle.

Stört der eine optionale Parameter den anderen? Ich habe nun die zweite Prozedurdeklaration gewählt, damit es klappt. Aber so recht verstehe ich den Effekt nicht. Die Parameter als const-Paramter zu definieren bringt nichts, gleicher Effekt.

Hat irgendwer einen Gedanken, wieso das so ist?

_________________
Toleranz ist eine Grundvoraussetzung für das Leben.
WasWeißDennIch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: Mo 28.01.13 08:52 
Hast Du evtl. noch versehentlich eine lokale Variable gleichen Namens deklariert? Unter Delphi 7 (ältere Versionen habe ich nicht installiert) kann ich das Verhalten jedenfalls nicht nachvollziehen.
Tranx Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 648
Erhaltene Danke: 85

WIN 2000, WIN XP
D5 Prof
BeitragVerfasst: Mo 28.01.13 13:04 
Ich habe bei dem Programm (die Parameter sind nur Beispiel) eine strikte Trennung zwischen lokalen/globalen Variablen und Parametern vorgenommen.

Lokale Variablen beginnen mit einem kleinen l, gefolgt von einem Kleinbuchstaben, aus dem ich die Art der Variablen erkenne: z.B. i für Ganzzahl, e für Float, o für Object, s für String ...

Globale Variablen habe ich wie folgt gekennzeichnet: beginnendes kleines g und dann kleine Kennzeuchnung wie lokale Variable.

Parameter fangen mit einem kleinen p an.

Also sieht der Prozeduraufruf beispielhaft wie folgt aus:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
procedure ProcName(psText : string; psZusatz : string = ''; piTyp : integer = 10);
var
  lsTest : String;
  liVar1 : Integer;
begin
  lsTest := psText + #10#13// Beispiel, zur Verdeutlichung der Vorgehensweise
  if piTyp<10 then
    TueIrgendwas(lsTest);
  else
    TueWasAnderes(lsTest);
end;


So ist eine Verwechslung nicht möglich. Sieht zwar nicht wirklich toll aus, aber ich kann viel einfacher über mehrere Quelltexte bestimmte Größen in ihrem Namen ändern und auch viel einfacher Variablen von Parametern und Funktionsaufrufen unterscheiden. Funktionen/Prozeduren beginnen mit einem Großbuchstaben.

Auch kann ich sofort den Typ der Variablen und Parameter erkennen, was bei Namen wie : Value, Wert, Inhalt ... nicht möglich ist.

folgende Typzeichen habe ich belegt:
a: Array mit anschließendem Typ der Variable (ae = z.B. Array[1..12] of double)
b: boolean
c: char
e: extended, double, single ...
f: procedure/function
i: integer, byte, word, dword, longint
m: Set (Menge) z.B. Set of Char;
o: Objekt/Klasse (z.B. TList, TObject, TButton....)
p: Pointer
r: record
s: string
t: TDateTime
v: Variant

Einzig Variablen wie i, s, n habe ich nicht geändert, nur konsequenterweise klein geschrieben. Auch die Parameter Sender, Value (bei Property) und andere vordeklarierte Parameter von Delphi habe ich nicht geändert, selbstverständlich auch nicht Self!

So kann ich jetzt auch Delete oder Text verwenden, eben mit den vorgenannten Buchstaben: z.B. lbDelete, lsText, psText ...

Wahrscheinlich, muss mal sehen, werde ich auch Records entsprechend ausstatten (mit vorangestelltem r) Dann sieht man sofort, was Record-Eigenschaften sind. Oder auch Klassenvariablen (vorangestelltes f).

z.B.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
type
  grTest = record
             rsEintrag : string;
             rbGelesen : boolean;
           end;




Da keine Verwechslung vorliegt ist der Effekt eben immer noch nicht klar. Aber es funktioniert mit einem optionalen Paramter.

_________________
Toleranz ist eine Grundvoraussetzung für das Leben.
WasWeißDennIch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: Mo 28.01.13 13:13 
Wie gesagt, unter Delphi 7 funktioniert es auch mit 2 optionalen Parametern. Wenn Verwechslungen wirklich zu 100% auszuschließen sind, scheint es sich tatsächlich um einen Delphi-Bug zu handeln. Das sollte aber jemand mit Delphi 5 verifizieren.
Marc.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1876
Erhaltene Danke: 129

Win 8.1, Xubuntu 15.10

BeitragVerfasst: Mo 28.01.13 13:35 
Unter Delphi2009 ist der Bug auch nicht zu beobachten.

Das ist nun von meiner Seite einfach mal ins Blaue geschossen:
Wie sieht denn der erzeugte Code aus? Scheinbar werden ja die Parameter falsch übergeben. :gruebel:

Dazu am besten mal ein neues Projekt nur mit dem relevanten Code anlegen, sowie im ersten Beitrag. Dann einen Breakpoint auf die aufzurufende Funktion setzen und mit Strg+Alt+C einmal in den Assembler-Code und Stack schauen.
Das sollte dann, wenn alles korrekt ist, in etwa so aussehen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
Unit1.pas.36: Procname('Test');
0046CD0C B90A000000       mov ecx,$0000000a // c = 10
0046CD11 33D2             xor edx,edx // b = ''
0046CD13 B82CCD4600       mov eax,$0046cd2c // a = 'Test'
0046CD18 E877FFFFFF       call Procname

Die Parameter-Werte werden den Registern direkt übergeben.
Anschließend mal durchsteppen und schauen, ob bereits vor oder erst in der Procname-Funktion das entsprechende Register irgendwo überschrieben wird. :?

Der Problem erinnert ein wenig an diesen Bug, auch wenn hier keine Overload-Direktiven dabei sind. :nixweiss:


Schöne Grüße

Für diesen Beitrag haben gedankt: Tranx
Tranx Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 648
Erhaltene Danke: 85

WIN 2000, WIN XP
D5 Prof
BeitragVerfasst: Mo 28.01.13 15:05 
Ich habe es mal mit einer leeren Anwendung probiert. Da klappt es. Scheint doch irgendwo in meinem Programm eine Wechselwirkung zu existieren. Das hatte ich mit anderen Dingen hier udn da mal, z.B. wenn ich die Komponenten TFBook eingebunden hatte, gab es unkontrolliert Probleme mit z.B. TQuery-Komponenten, die dann unerklärlicherweise nicht auf active gesetzt werden konnte. Wenn ich dann nur die TFBook-Komponenten aus dem Programm nahm, funktionierte wieder alles.

Auf jeden Fall danke für die Hinweise. Werde mal die Registerbelegung genauer untersuchen.

_________________
Toleranz ist eine Grundvoraussetzung für das Leben.