Gleichheit von zwei Structs?
-
ich frage mich ob man für einen "flachen" Vergleich (Vergleich der einzelnen Datenelemente) einer Struktur (struct) den equals Operator verwenden kann bzw. ob die Programmiersprache C es vorsieht, das dieser für einen flachen Vergleich verwendet werden kann
#include <stdio.h> typedef struct vector2d { float x; float y; } vector2d; void setVector2d(float x, float y, vector2d *v) { v->x = x; v->y = y; } int main(void) { vector2d a, b; setVector2d(1, 4, &a); b = a; if(a==b) { print("a gleich b\n"); } else { print("a nicht gleich b\n"); } }
b = a funktioniert - a == b übersetzt mein Compiler (gcc) nicht - finde es irgendwie komisch, das die Zuweisung zwar erlaubt ist, aber ein vergleich nicht möglich ist... vielleicht wollte man damit aber auch den Gefahren einer Referenzgleichheit anstatt einer inhaltlichen Gleichheit aus dem Weg gehen?
-
Frage 9.5: Warum kann man Structs nicht vergleichen?
Antwort: Es gibt keinen vernünftigen Weg für einen Compiler, Vergleiche von Structs zu implementieren, der konsistent zu C's low-level Konzept ist. Ein Byte für Byte Vergleich könnte durch zufällige Bits in den Löchern einer Struktur (wenn Padding verwendet wird, um die Ausrichtung der späteren Felder korrekt zu halten; siehe Fragen 9.10, 9.11) verfälscht werden. Ein Feld für Feld Vergleich würde bei großen Strukturen inakzeptable Mengen an wiederholtem Inlinecode benötigen.
Zum Vergleich von zwei Structs kommt man nicht umhin, eine Funktion zu schreiben, die das tut. Unter C++ kann dazu der == Operator überladen werden.
References: K&R II Sec. 6.2 p. 129; H&S Sec. 5.6.2 p. 103; ANSI Rationale Sec. 3.3.9 p. 47.
von
http://www2.informatik.uni-wuerzburg.de/dclc-faq/kap9.html
-
Ein Feld für Feld Vergleich würde bei großen Strukturen inakzeptable Mengen an wiederholtem Inlinecode benötigen.
was soll daran inakzeptabel sein?
-
Vertexwahn schrieb:
b = a funktioniert - a == b übersetzt mein Compiler (gcc) nicht -
wie soll der Compiler denn wissen, wie er deine Structs vergleichen soll? Du musste selber eine Funktion bereitstellen, die das zurückliefert, weil structs nicht immer auf die gleiche Art und Weise vergliechen werden können, bsp:
typdef struct s1 { char* x; char* y; int z; } t_s1;
Wenn der Compiler automatisch bei a==b folgendes machen würde (a.x==b.x && a.y==b.y && a.z == b.z) dann würde das in den meisten Fällen FALSE zurückgeben, denn strcmp(a.x,b.x) wäre da vernünftiger. Siehst du, woher soll der Compiler sich all das überlegen?
-
wie soll der Compiler denn wissen, wie er deine Structs vergleichen soll?
man könnte einfach definieren das der equals operator einfach einen "flachen" Vergleich macht so wie der zuweisungsoperator eine flache Kopie macht
das war aber gar nicht die Frage
Ein Feld für Feld Vergleich würde bei großen Strukturen inakzeptable Mengen an wiederholtem Inlinecode benötigen.
wo liegt da das Problem?
naja ich finde die Begründung für die Frage 9.5 sinnlos
Zitat/Begründung:
gibt keinen vernünftigen Weg für einen Compiler, Vergleiche von Structs zu implementieren
doch gibt es - falcher vergleich
Ein Byte für Byte Vergleich könnte durch zufällige Bits in den Löchern einer Struktur (wenn Padding verwendet wird, um die Ausrichtung der späteren Felder korrekt zu halten; siehe Fragen 9.10, 9.11) verfälscht werden.
der Compilerhersteller wird doch wissen welches Bytepadding er verwendet
- das ist technisch lösbar
Ein Feld für Feld Vergleich würde bei großen Strukturen inakzeptable Mengen an wiederholtem Inlinecode benötigen.
yup - aber wie will man den sonst "große" Strukturen vergleichen - irgendwo muss man halt mal Datenelement für Datenelment vergleichen
-
das blöde ist ja, dass die padding bits theoretisch zufälligen inhalt haben können, aber wenn man seine structs byte-aligned packt, dann sollte 'memcmp' gehen.
-
Vertexwahn schrieb:
der Compilerhersteller wird doch wissen welches Bytepadding er verwendet
- das ist technisch lösbar
Das weisst du ja sogar als Programmierer.
Wenn man es richtig anstelllt, kann man structs durchaus mit memcmp() vergleichen.
-
das blöde ist ja, dass die padding bits theoretisch zufälligen inhalt haben können
es gibt aber sprachmittel, mit welchen man den Abstand zwischen zwei Datenelementen in einer Struktur ermitteln kann - warum sollte man den padding bits auch vergleichen - macht doch keinen sinn
-
Vertexwahn schrieb:
es gibt aber sprachmittel, mit welchen man den Abstand zwischen zwei Datenelementen in einer Struktur ermitteln kann
differenz der adressen? was hilft dir das?
Vertexwahn schrieb:
- warum sollte man den padding bits auch vergleichen - macht doch keinen sinn
na wenn man 'memcmp' benutzt scheitert das ja an den padding bits. das geht nur gut, wenn keine padding bits da sind (#pragma pack(1) o.ä.)
-
net schrieb:
na wenn man 'memcmp' benutzt scheitert das ja an den padding bits. das geht nur gut, wenn keine padding bits da sind (#pragma pack(1) o.ä.)
Oder wenn man konsequent den Speicher der Strukturen vor der Benutzung auf einen definierten Wert setzt (ist ja egal welcher). Also immer schön callocen
-
TactX schrieb:
net schrieb:
na wenn man 'memcmp' benutzt scheitert das ja an den padding bits. das geht nur gut, wenn keine padding bits da sind (#pragma pack(1) o.ä.)
Oder wenn man konsequent den Speicher der Strukturen vor der Benutzung auf einen definierten Wert setzt (ist ja egal welcher). Also immer schön callocen
benutzt du nur heap-variablen?
-
Nö. aber dazu gibt's memset()
-
TactX schrieb:
Nö. aber dazu gibt's memset()
cool. das isses. vor dem füllen der structs erstmal 'memset(&x, 0, sizeof(x))' und dann zum vergleichen 'memcpy()'. vertex: deine frage ist beantwortet
-
memcpy()?
Oder war das der Gag zum Smilie den ich nicht geblickt hab?
-
TactX schrieb:
memcpy()?
Oder war das der Gag zum Smilie den ich nicht geblickt hab?
kein gag. ich meinte 'memcmp()' hab mich verschrieben.
-
net schrieb:
TactX schrieb:
memcpy()?
Oder war das der Gag zum Smilie den ich nicht geblickt hab?
kein gag. ich meinte 'memcmp()' hab mich verschrieben.
ich glaube, memcmp ist das auch nicht ganz toll, wenn man folgendes hat:
struct wasweissich { char* str1; int c; }
denn sinnvoll wäre, wenn str1 von dem einem Struct das selbe Strings hätten, wie str1 von dem anderen struct, sprich bei
struct wasweissich a; struct wasweissich b; /* mache etwas mit a */ /* mache etwas mit b */ copmarestructs_with_memcpm(a,b);
da könnte es sein, dass a.str1 != b.str1 aber strcmp(a.str1,b.str1)==0, mit memcmp würde man aber FALSE haben, weil a.str1 != b.str1
-
Das ist klar, solche Fälle muss man dann halt speziell behandeln.
-
klar, kommt drauf an, wie man 'gleichheit' von structs definiert. ich würde sagen man sollte die structs als 'flach' ansehen, wenn sie byte-aligned sind bzw. vor der initialisierung mit memset() geplättet wurden und dann memcmp() klappt, sind sie auf jeden fall gleich. alles andere führt zu weit, dafür bräuchte man ja sowas wie 'reflection' in java (in c++ schimpft sich das doch 'rtti' nicht?), au weia