Autor |
Beitrag |
DrRzf
      
Beiträge: 260
Win XP Prof
D7 Enterprise
|
Verfasst: So 02.12.07 00:59
Ich schreibe gerade ein Programm das Konstruktionslisten eines Browsergames auswertet.
Diese Listen sehen so aus
Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| Zivilgebäude Hauptquartier (100) Kosten: 3.983.000 Eisen - 637.280 Titan - 3 Tage 17:14:54 bauen Biozelle (74) Kosten: 1.793.700 Eisen - 398.600 Titan - 22:25:00 bauen Bunker (32) Kosten: 727.500 Eisen - 291.000 Titan - 09:59:24 bauen Rohstoffgebäude Farm (60) Kosten: 369.300 Eisen - 0 Titan - 11:34:27 bauen Eisenmine (62) Kosten: 497.625 Eisen - 33.175 Titan - 19:57:32 bauen Titanmine (29) Kosten: 116.000 Eisen - 2.320 Titan - 03:33:07 bauen usw, usf.... |
diese Listen werden nach Gebäudeart, Stufe, Eisen-, und Titankosten und Bauzeiten abgesucht
und in folgendem Datentyp zwischengespeichert.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| Type TKonstruktion = record Min : integer; Max : integer; Stufe : integer; Art : integer; HQ : integer; Fe : int64; Ti : int64; Zeit : int64; end; |
folgender Code erledigt die Suche nach gebäudeart, und aufruf eine function die Eisen, Titan und Bauzeiten ausliest.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29:
| procedure TForm1.BtnAuswertenClick(Sender: TObject); var i,c,x,hq : integer; str : string; k : TKonstruktion; begin c := MemoI.Lines.Count; ClearKIn(k); hq := - 1; SetLength(Kin,0); for i := 1 to c do begin str := MemoI.Lines[i-1]; for x := 1 to AnzKonst - 4 do if pos(Konststr[x],str) > 0 then begin K.Art := x; K := AnalyzeData(str); if x = 1 then begin hq := K.Stufe; end; K.HQ := hq - 1; K := AnalyzeMinMax(K); AddKin(K); end; end; UpdateOutGrid; end; |
und nun zu meinem Problem.
In Zeile 17 wird K.Art gesetzt.
In folgender Zeile wird K komplett durch
K := AnalyzeData(str);
überschrieben. wieso habe ich also nach aufruf dieser function immer noch, K.Art richtig in der Variable ?
sie wird in AnalyzeData weder neu gesetzt noch verändert, also sollte doch hier weis der geier was zurückkommen.
hier die function AnalyzeData.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48:
| function AnalyzeData(str : string): TKonstruktion; var pa,pe,i : integer; s,sstr : string; begin pa := pos('(',str); pe := pos(')',str); if pa > 0 then begin s := copy(str,pa+1,pe - pa - 1); result.Stufe := StrToIntDef(s,-1) + 1; end else begin result.Stufe := 1; end; pa := pos(':',str); sstr := copy(str,pa+1,length(str)-3);
pa := 0; pe := pos('Eisen',sstr); s := ''; for i := pa to pe - 1 do begin if StrToIntDef(sstr[i],-1) > -1 then s := s + sstr[i]; end; result.Fe := StrToInt64(s);
pa := pos('Eisen',sstr); pe := pos('Titan',sstr); s := ''; for i := pa + 6 to pe - 1 do begin if StrToIntDef(sstr[i],-1) > -1 then s := s + sstr[i]; end; result.Ti := StrToInt64(s);
pa := pos('Titan',sstr); pe := pos(':',sstr); s := copy(sstr,pa + 8,pe - pa); result.Zeit := TimeToSecond(s); result.Min := 0; result.Max := 0; end; |
kann das evtl daran liegen dass ich hier mit result arbeite, und dieses eigentlich nicht den wert ''zurückliefert'' sondern bereits direkt auf die variable in BtnAuswertenClick zugreift ?
_________________ rein statistisch gesehen darf man keiner statistik trauen die man nicht selbst gefälscht hat.
|
|
JayEff
      
Beiträge: 2971
Windows Vista Ultimate
D7 Enterprise
|
Verfasst: Di 04.12.07 14:52
In deiner Funktion AnalyzeData wird result.Art nicht gesetzt, oder? Dann wird vermutlich deshalb der zuvor gesetzte Wert nicht überschrieben
Du konstruierst in der Funktion das Objekt und gibst es am Ende zurück. Bei Objekten werden iirc Delphi-Intern nur Zeiger übergeben, aber genau erklären kann ich mir das nicht - Vielleicht sollte da mal einer von den Profis ran 
_________________ >+++[>+++[>++++++++<-]<-]<++++[>++++[>>>+++++++<<<-]<-]<<++
[>++[>++[>>++++<<-]<-]<-]>>>>>++++++++++++++++++.+++++++.>++.-.<<.>>--.<+++++..<+.
|
|
Narses
      

Beiträge: 10183
Erhaltene Danke: 1256
W10ent
TP3 .. D7pro .. D10.2CE
|
Verfasst: Di 04.12.07 15:09
Moin!
JayEff hat folgendes geschrieben: | Du konstruierst in der Funktion das Objekt und gibst es am Ende zurück. Bei Objekten werden iirc Delphi-Intern nur Zeiger übergeben, aber genau erklären kann ich mir das nicht - Vielleicht sollte da mal einer von den Profis ran  |
Was für ein Objekt?  Das Ding ist doch "nur" ein record und deshalb ist Result einfach "vorhanden".
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
JayEff
      
Beiträge: 2971
Windows Vista Ultimate
D7 Enterprise
|
Verfasst: Di 04.12.07 15:13
 entschuldigung - aber die Antwort ist immernoch nicht ganz klar - werden in diesem Beispiel nur "gesetzte" werte überschrieben?
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| type x = record a, b, c : Integer; x, y : String; end;
x1, x2 : x; begin x1.a := 5; x1.y := "hallo";
x2.b := 1; x2.c := 1; x2.x := "blah";
x1 := x2; |
ist in x1.a nun die 5, in x1.y das "hallo" ? oder wurden die Werte mit den Werten überschrieben, mit denen die Eigenschaften von x2 initialisiert wurden?
_________________ >+++[>+++[>++++++++<-]<-]<++++[>++++[>>>+++++++<<<-]<-]<<++
[>++[>++[>>++++<<-]<-]<-]>>>>>++++++++++++++++++.+++++++.>++.-.<<.>>--.<+++++..<+.
|
|
Narses
      

Beiträge: 10183
Erhaltene Danke: 1256
W10ent
TP3 .. D7pro .. D10.2CE
|
Verfasst: Di 04.12.07 15:46
Moin!
JayEff hat folgendes geschrieben: | ist in x1.a nun die 5, in x1.y das "hallo" ? oder wurden die Werte mit den Werten überschrieben, mit denen die Eigenschaften von x2 initialisiert wurden? |
Probier´s doch mal eben aus.
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
Sinspin
      
Beiträge: 1335
Erhaltene Danke: 118
Win 10
RIO, CE, Lazarus
|
Verfasst: Di 04.12.07 18:32
Die Sache ist ganz einfach. Erstmal ist Result eine Variable der Funktion. Damit dürfte sie, wie alle anderen Variablen auch, auf dem Stack liegen. Stackvariablen enthalten den Wert der an der Stelle im Speicher steht an dem sich Variable befindet. Damit steht da immer schon irgendwas drinne.
Im Normalfall mault der Compiler eine Warnung raus wenn du auf eine Variable lesend zugreifst ohne sie vorher belegt zu haben. Das gleiche kommt wenn du Result nicht beschreibst bevor die Funktion beendet ist.
Result ist in deinem Fall zusammengesetzt, womit es sich für den Compiler erledigt hat wenn du einen Wert von Result beschreibst.
Die anderen Werte von Result enthalten aber noch immer das was ursprünglich auf dem Stack stand. Dass das in deinem Fall gerade passt ist Zufall.
Am Ende der Funktion wird dann einfach der gesammte Inhalt des Speicherbereiches, den Result belegt hat, in deine Variable kopiert. Somit hast du dann alles dort was in Result stand.
_________________ Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
|
|
DrRzf 
      
Beiträge: 260
Win XP Prof
D7 Enterprise
|
Verfasst: Di 04.12.07 22:18
Dass hier der zufall ne rolle Spielt kann ich fast nicht glauben.
Ich habe in den 2 tagen bevor mir das aufgefallen ist, ca 500 solcher listen ausgewertet, wobei jede liste im schnitt ca 20 - 24 einträge hat. 500 * 20 = 10.000 mal dass dieser result zurückgegeben wurde, aber es ist kein einziger Fehler aufgetreten. Sonst würde bei einem Fehler auch die nachfolgende berechnung nicht mehr stimmen da fast jedes Gebäude andere Grundwerte besitzt und die für die berechnung massgebend sind.
Edit:
Habe grad 3 Zeilen Code in das Programm eingefügt um die Anzahl der Einträge zu ermitteln.
Insgesamt sind jetzt 6833 Einträge in der Tabelle. Hier wurden aber bereits Doppelte beim Adden der Daten eliminiert.
_________________ rein statistisch gesehen darf man keiner statistik trauen die man nicht selbst gefälscht hat.
|
|
Sinspin
      
Beiträge: 1335
Erhaltene Danke: 118
Win 10
RIO, CE, Lazarus
|
Verfasst: Di 04.12.07 22:45
Nein, diese Art von Zufall meine ich nicht.
Dieser Zufall liefert bei einem Programm dessen relevante Teile nicht geändert werden immer das gleiche Ergebnis.
Irgendwo in deinem Programm ist eine Prozedur oder Funktion die an genau diese Speicherstelle den wert schreibt den du später dort findest.
Du kannst das ja ganz einfach prüfen indem du mal Result.Art in deiner Funktion entsprechend belegst. Wenn es dann immernoch nicht passt schaun mer mal.
_________________ Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
|
|
DrRzf 
      
Beiträge: 260
Win XP Prof
D7 Enterprise
|
Verfasst: Di 04.12.07 23:15
Ich hab grad mal ne andere Idee gesponnen....
4 Edits und ein Button.
neues Programm, selbe vorgehensweise. nur dass ich hier die ersten 3 variablen in Test beschreibe, und die 4te in einer function aus den ersten 3 berechnen lasse. funktioniert astrein
Ich kann also in der function die in der vorhergehenden procedure gesetzten werte abrufen, ohne dass diese übergeben werden.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54:
| unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type TForm1 = class(TForm) Edit1: TEdit; Edit2: TEdit; Edit3: TEdit; Edit4: TEdit; Button1: TButton; procedure Button1Click(Sender: TObject); private public end;
type TTest = record A : integer; B : integer; C : integer; D : integer; end;
var Form1: TForm1;
implementation
{$R *.dfm}
function TestMich(): TTest; begin result.D := result.A * result.B * result.C; end;
procedure TForm1.Button1Click(Sender: TObject); var Test : TTest; begin Test.A := StrToInt(Edit1.Text); Test.B := StrToInt(Edit2.Text); Test.C := StrToInt(Edit3.Text); Test := TestMich; Edit4.Text := IntToStr(Test.D); end;
end. |
_________________ rein statistisch gesehen darf man keiner statistik trauen die man nicht selbst gefälscht hat.
|
|
JayEff
      
Beiträge: 2971
Windows Vista Ultimate
D7 Enterprise
|
Verfasst: Mi 05.12.07 09:59
Interessant, aber immernoch Zufall. Was das ausprobieren betrifft: Auf den Linuxrechnern in der Uni ist kein Delphi installiert 
_________________ >+++[>+++[>++++++++<-]<-]<++++[>++++[>>>+++++++<<<-]<-]<<++
[>++[>++[>>++++<<-]<-]<-]>>>>>++++++++++++++++++.+++++++.>++.-.<<.>>--.<+++++..<+.
|
|
OlafSt
      
Beiträge: 486
Erhaltene Danke: 99
Win7, Win81, Win10
Tokyo, VS2017
|
Verfasst: Mi 05.12.07 14:29
Ich glaube da nicht mehr an einen Zufall - eher an eine Optimierung. Es wäre durchaus Schlau, anstelle erst einen neuen Record zu allozieren und den in den Ergebnisrecord zu kopieren, auch gleich die Adresse des Ergebnisrecords zu verwenden. Der Compiler kennt ja alle nötigen Informationen.
Wäre interessant zu erfahren, ob das ganze im {$O-} auch noch funktioniert...
_________________ Lies, was da steht. Denk dann drüber nach. Dann erst fragen.
|
|
Sinspin
      
Beiträge: 1335
Erhaltene Danke: 118
Win 10
RIO, CE, Lazarus
|
Verfasst: Mi 05.12.07 15:19
Zitat: | Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| function TestMich(): TTest; begin result.D := result.A * result.B * result.C; end;
procedure TForm1.Button1Click(Sender: TObject); var Test : TTest; begin Test.A := StrToInt(Edit1.Text); Test.B := StrToInt(Edit2.Text); Test.C := StrToInt(Edit3.Text); Test := TestMich; Edit4.Text := IntToStr(Test.D); end; | |
Hm, das ist wunderlich.
Aber wenn man es mal genau betrachtet, dann ist ja "Test" in dem Moment mit "Result" verbunden wo die Funktion aufgerufen wird. Denn egal wie die Funktion verlassen wird, "Result" wird IMMER in der Variablen stehen.
Außer bei Exceptions natürlich, aber das ist ja dann eh alles unbrauchbar.
Es gibt letztendlich für "Test" keine Möglichkeit an der Befüllung durch "Result" vorbei zu kommen. Somit wäre es eine Optimierung, dafür den gleichen Speicherbereich zu verwenden.
Ich würde mich nur nicht darauf verlassen dass das immer so ist, solange ich das noch nicht Schwarz auf Weiß in der Delphi Doku gelesen habe.
_________________ Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
|
|
DrRzf 
      
Beiträge: 260
Win XP Prof
D7 Enterprise
|
Verfasst: Mi 05.12.07 19:47
Die Werte werden auch schon beim debuggenm korrekt in der function angezeigt.
Auch wenn ich die reihenfolge der zuweisung auf ABC verändere bleibt das ergebnis korrekt.
wenn ich den Wert in Test.C nach der function erst beschreibe steht in dieser erwartungsgemäss irgend ein zufälliger wert. Ich hab ja schon die befürchtung dass hier als result mit einem Zeiger auf die variable in der ersten procedure gearbeitet wird. dadurch würde dann beim verlassen der function ein extra übertragen der erbegniss auf die andere Variable entfallen.
man sollte sich das villeicht mal ansehn wie das ganze als assembler aussieht.
wie funzt das gleich nochmal ?
Edit:
Ich hab in der orginalprocedure die zuweisung jetzt umgedreht. will mich da auch nicht grad drauf verlassen.
_________________ rein statistisch gesehen darf man keiner statistik trauen die man nicht selbst gefälscht hat.
|
|
OlafSt
      
Beiträge: 486
Erhaltene Danke: 99
Win7, Win81, Win10
Tokyo, VS2017
|
Verfasst: Do 06.12.07 13:49
Ich habe mir das ganze mal im Assembler-code angesehen - und ich hatte recht. Tatsächlich wird mit dem vorgefülten Record gearbeitet:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| Unit7.pas.46: Test.A := StrToInt(Edit1.Text);
00454C05 8D55EC lea edx,[ebp-$14] 00454C08 8B8360030000 mov eax,[ebx+$00000360] 00454C0E E8511DFEFF call TControl.GetText 00454C13 8B45EC mov eax,[ebp-$14] 00454C16 E85939FBFF call StrToInt 00454C1B 8945F0 mov [ebp-$10],eax
Unit7.pas.47: Test.B := StrToInt(Edit2.Text); <snip> Unit7.pas.48: Test.C := StrToInt(Edit3.Text); <snip> Unit7.pas.49: Test := TestMich;
00454C50 8D45F0 lea eax,[ebp-$10] 00454C53 E878FFFFFF call TestMich
Unit7.pas.50: Edit4.Text := IntToStr(Test.D); <snip> |
An Adresse $454C50 sieht man es: In EAX wird die Adresse von Test geladen, dann die function aufgerufen. In der Function wird dann mit diesem EAX (und somit dem klammheimlich übergebenen Record) weitergearbeitet:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| Unit7.pas.39: result.D := result.A * result.B * result.C;
00454BD0 8B10 mov edx,[eax] 00454BD2 0FAF5004 imul edx,[eax+$04] 00454BD6 0FAF5008 imul edx,[eax+$08] 00454BDA 89500C mov [eax+$0c],edx
end;
00454BDD C3 ret |
Sowohl mit als auch ohne Optimierung ändert sich nichts an diesem Verhalten. Das ganze ist also von Borland so gewollt, scheint mir (getestet mit Turbo Delphi Professional 2006).
_________________ Lies, was da steht. Denk dann drüber nach. Dann erst fragen.
|
|
|