PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [Delphi] Records auf Gleichheit prüfen



Whiz-zarD
13.02.2010, 18:27
Moin.
Ich schreib mir grad eine kleine Bibliothek für eine einfachverkettete Liste.
Dafür hab ich ein Record, welches die Knoteninformationen (was ebenfalls ein Record ist) und den Zeiger auf den nächsten Knoten beinhaltet.

Nun möchte ich eine Funktion schreiben, die überprüft, ob ein bestimmter Knoten schon existiert. Da ich die Bibliothek nun unabhängig von den Records haben möchte, muss ich die Records, die die Knoteninformationen beinhalten, auf Gleichheit prüfen.
Nur leider kann man nicht mit if Record1= Record2 auf Gleichheit prüfen.
Jemand ne Idee, wie man sowas realisieren kann?

Desmulator
13.02.2010, 18:34
Solange die Records vom selben Typen sind, sollte if Record1 = Record2 funktionieren.

Whiz-zarD
13.02.2010, 18:42
anscheinend wohl nicht, da der Kompiler die Fehlermeldung:

"E2015 Operator ist auf diesen Operandentyp nicht anwendbar"

ausspuckt.

Brauni90
13.02.2010, 20:03
Auch wenn ich Delphi nicht kenne. Kannst du das relevante Stueck, an dem es hapert zeigen?

Whiz-zarD
13.02.2010, 20:13
Es ist im Grunde nichts besonderes.
Typendefinition:


//Alle Werte eines Feldes
PField = ^TField;

TInfo = record
row, col : TRowCol; //Position im gesamten Spielfeld
player : TPlayer;
selected : boolean;
end;

TField = record
Info : TInfo;
p : array[TPointerDirection] of PField; //Zeiger auf die Nachbarfelder
pNext : PField; //lineare Verkettung
end;

Den Rest der Typendefinition hab ich mal weggelassen.

Funktion:


function list_isIn(I:TInfo; F:PField):boolean;
begin
if I = F^.Info then
list_isIn := true
else
list_isIn := list_isIn(e, list_tail(l));
end;

list_tail() liefert nur den pNext-Zeiger

Ineluki
13.02.2010, 20:59
Loesungsansatz 1:

function is_equal(a,b:Record): Boolean;
begin
is_equal := true;
is_equal := is_equal or ( a.x = b.x );
is_equal := is_equal or ( a.y = b.y );
is_equal := is_equal or ( a.z = b.z );
..
end;

Loesungsansatz 2: Du verwendest statt Records Objekte und bietest obige Funktion als Methode an.

Whiz-zarD
13.02.2010, 21:33
Loesungsansatz 1:

function is_equal(a,b:Record): Boolean;
begin
is_equal := true;
is_equal := is_equal or ( a.x = b.x );
is_equal := is_equal or ( a.y = b.y );
is_equal := is_equal or ( a.z = b.z );
..
end;


Genau das wollte ich eigentlich verhindern.
Ich wollte es ganz gerne unabhängig von der Struktur des Records lösen.
So muss ich ja jedes Mal, wenn sich die Struktur des Records ändert, auch die Funktion ändern.

Dass mit den Objekten muss ich mir mal genauer anschauen, da ich noch nie mit Objekten gearbeitet habe und die Records leider vorgegeben worden sind (ist eine Aufgabe für die Schule).

Brauni90
14.02.2010, 02:49
Wenn du es mit einer sich aendernden, nicht anpassbaren Struktur zu tun hast, dann wird es etwas schwierig. Andererseits koenntest du eine Variable fuer die Groesse in die Records aufnehmen. Zur Verarbeitung bieten sich Zeigerarithmetik (http://de.wikipedia.org/wiki/Zeiger_(Informatik)) und Schleifen (http://www.delphi-treff.de/sprachen/object-pascal/schleifen/) an, falls ihr das schon angesprochen hattet.

Ineluki
14.02.2010, 06:43
Ok, es gibt noch eine fiese Quick n' Dirty Methode fuer Records.
Allerdings nur, wenn sie wirklich von absolut dem selben Typ sind und keinerlei dynamische Strukturen aufweisen.

Dann koenntest du direkt auf binaere Identitaet pruefen mittels

Unit Sysutils
function CompareMem(P1, P2: Pointer; Length: Integer): Boolean; assembler;

Du machst die Funktion

function is_equal(R1, R2: Record): Boolean;
begin
is_equal := CompareMem( @R1, @R2, SizeOf(Record) )
end;

Damit ueberpruefst du, ob der Speicherinhalt an den Speicherstellen @R1 und @R2 innerhalb einer Laenge von SizeOf(Record) Bytes identisch ist. SizeOf(Record) liefert gerade die Laenge deines Record-Typs in Byte.
Das ganze geht natuerlich massiv in die Hose, wenn der Record eine dynamische Laenge besitzt (wie es z.B. manche Datentypen der Windows-API haben) und pro Instanz demnach unterschiedlich lang sein kann.

Ausserdem gibts natuerlich Probleme, wenn dein Record selber Zeiger enthaellt. MemComp ueberprueft naemlich durch den byteweisen Vergleich, ob die Addressen, auf die die Zeiger zeigen, identisch sind, nicht, ob deren Inhalt identisch ist. Nehmen wir also an, du haettest einen Record R1 und einen Record R2, die beide einen typisierten Pointer P besitzen, (der auch auf alloziierten Speicher zeigt). Dann wuerde R2.P^ := R1.P^; eine Valide Zuweisung sein, indem der Inhalt von R2.P durch den Inhalt von R1.P ersetzt wird. Dennoch zeigen R1.P und R2.P auf unterschiedliche Speicherbereiche (Addressen), und MemComp schlaegt damit als binaerer Vergleich fehl, obwohl der Inhalt beider Zeiger (aber nicht beide Zeiger) identisch sind.

Whiz-zarD
14.02.2010, 08:59
Wenn du es mit einer sich aendernden, nicht anpassbaren Struktur zu tun hast, dann wird es etwas schwierig. Andererseits koenntest du eine Variable fuer die Groesse in die Records aufnehmen. Zur Verarbeitung bieten sich Zeigerarithmetik (http://de.wikipedia.org/wiki/Zeiger_(Informatik)) und Schleifen (http://www.delphi-treff.de/sprachen/object-pascal/schleifen/) an, falls ihr das schon angesprochen hattet.

Ich weiß, was Schleifen und Zeiger sind. Ist ja nicht so, dass ich schon seit Jahren programmiere und nun ins vierte Semester meiner Ausbildung komme ;)

Ich hab mir ja so eine Bibliothek unter C geschrieben und wollte sie jetzt nach Delphi übertragen, da ich nun solche Funktionen für eine Seminaraufgabe brauche. Unter C geht es ja mit if (struct1 == struct2), nur leider wohl unter Delphi nicht.

Ok, da man wohl unter Delphi mit dreckigen und unsicheren Tricks arbeiten muss, dann lass ich wohl diese Funktionen raus, die von dieser Funktion abhängig sind. Je weniger murks da drinnen steht, desto weniger können sie danach fragen ^^

Ineluki
14.02.2010, 09:14
Was hast du erwartet ?

Du wusstest schon selber, dass es keinen Vergleichsoperator fuer Records gibt.
Ergo gibt es nur 2 Moeglichkeiten:

a) Du vergleichst alles per Hand.

Das wolltest du aber nicht, da du dann, wenn du den Record aenderst, die Vergleichsfunktion anpassen musst.

b) Du pruefst die Speicherbereiche auf identischen Inhalt.

Das ist dir aber auch nicht recht, da es dir zu "dreckig" ist.

Nur andere Moeglichkeiten gibt es nun einmal nicht. Selbst die eingebauten Identitaetsoperatoren in C arbeiten auf diesem Prinzip (idR nach b, wobei die natuerlich schon vom compiler her auf Typgleichheit testen koennen).

Das ganze ist also kein "Delphi"-Problem, wie du es darstellst, sondern einfach, dass du etwas selbst implementieren musst, weil dir der syntaktische Zucker fehlt.

PS: Ganz nebenbei, ein "Danke" haette dir auch nicht geschadet.

Whiz-zarD
14.02.2010, 09:24
Was hast du erwartet ?
Hätte ja angehen können, dass es dafür eine spezielle Funktion in irgendeiner der Delphi Units gibt oder was weiß ich.



PS: Ganz nebenbei, ein "Danke" haette dir auch nicht geschadet.
Als ob darauf heutzutage noch großartig Wert draufgelegt wird ...

Danke

(warum auch immer diese aggressive Tonlage? ...)

Desmulator
14.02.2010, 12:42
Hätte ja angehen können, dass es dafür eine spezielle Funktion in irgendeiner der Delphi Units gibt oder was weiß ich.

Und wie hätte diese bitte aussehen sollen, wenn sie keinen Speichervergleich macht? RTTI? Soviel aufwand, nur um zwei Records zu vergleichen?

Kyuu
14.02.2010, 20:53
Es gibt in C keinen sprachunterstützten Vergleich von Strukturen, da die Möglichkeit besteht, dass Füllbytes eingesetzt werden. Insofern is der Speichervergleich Unsinn. In C++ gibt es die Möglichkeit den Vergleichsoperator zu überladen, das kommt allerdings einer eigenen Vergleichsfunktion gleich.