Autor Beitrag
DrRzf
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 260

Win XP Prof
D7 Enterprise
BeitragVerfasst: So 02.12.07 00:59 
Ich schreibe gerade ein Programm das Konstruktionslisten eines Browsergames auswertet.

Diese Listen sehen so aus
ausblenden 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.

ausblenden 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.

ausblenden 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 //gebäude gefunden
        begin
        K.Art := x;     //gebäude setzen
        K := AnalyzeData(str); //rohstoffe und zeiten auswerten
        if x = 1 then   //hq gefunden
          begin         //hq stufe setzen für folgende auswertungen
          hq := K.Stufe;
          end;
        K.HQ := hq - 1//hq stufe - 1 für grundwertberechnung
        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.

ausblenden volle Höhe 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:
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
//konstruktionsstufe auslesen
  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);

//eisen auslesen
  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);

//titan auslesen
  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);

//zeit auslesen
  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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2971

Windows Vista Ultimate
D7 Enterprise
BeitragVerfasst: 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 :nixweiss:
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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Di 04.12.07 15:09 
Moin!

user profile iconJayEff 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? :gruebel: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2971

Windows Vista Ultimate
D7 Enterprise
BeitragVerfasst: Di 04.12.07 15:13 
:oops: entschuldigung - aber die Antwort ist immernoch nicht ganz klar - werden in diesem Beispiel nur "gesetzte" werte überschrieben?
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Di 04.12.07 15:46 
Moin!

user profile iconJayEff 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. :idea: ;)

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1335
Erhaltene Danke: 118

Win 10
RIO, CE, Lazarus
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 260

Win XP Prof
D7 Enterprise
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1335
Erhaltene Danke: 118

Win 10
RIO, CE, Lazarus
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 260

Win XP Prof
D7 Enterprise
BeitragVerfasst: 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.

ausblenden volle Höhe 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:
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
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2971

Windows Vista Ultimate
D7 Enterprise
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 486
Erhaltene Danke: 99

Win7, Win81, Win10
Tokyo, VS2017
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1335
Erhaltene Danke: 118

Win 10
RIO, CE, Lazarus
BeitragVerfasst: Mi 05.12.07 15:19 
Zitat:
ausblenden 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 260

Win XP Prof
D7 Enterprise
BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 486
Erhaltene Danke: 99

Win7, Win81, Win10
Tokyo, VS2017
BeitragVerfasst: 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:

ausblenden 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]  //Übergibt Test an die function !!!
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:

ausblenden 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.