Wie vergleichen Sie zwei Instanzen von Strukturen auf Gleichheit in Standard C?
216
C bietet hierfür keine Sprachfunktionen - Sie müssen dies selbst tun und jede Struktur Mitglied für Mitglied vergleichen.
0.0, -0.0 NaN
ist ein Problem mitmemcmp()
. Zeiger, die sich in der binären Darstellung unterscheiden, können auf dieselbe Position zeigen (z. B. DOS: seg: offset) und sind daher gleich. Einige Systeme haben mehrere Nullzeiger, die sich gleichermaßen vergleichen lassen. Gleiches gilt für Obskurint
mit -0- und Gleitkommatypen mit redundanten Codierungen. (Intel Long Double, Decimal64 usw.) Diese Probleme machen keinen Unterschied, ob siecalloc()
verwendet werden oder nicht.==
nicht mit Strukturen arbeiten (wie ich), lesenSie könnten versucht sein, es zu verwenden
memcmp(&a, &b, sizeof(struct foo))
, aber es funktioniert möglicherweise nicht in allen Situationen. Der Compiler kann einer Struktur einen Ausrichtungspufferraum hinzufügen, und es wird nicht garantiert, dass die Werte, die an Speicherstellen gefunden werden, die im Pufferraum liegen, ein bestimmter Wert sind.Wenn Sie jedoch die Strukturen
calloc
odermemset
die volle Größe der Strukturen verwenden, bevor Sie sie verwenden, können Sie einen flachen Vergleich mit durchführenmemcmp
(wenn Ihre Struktur Zeiger enthält, stimmt sie nur überein, wenn die Adresse, auf die die Zeiger zeigen, identisch ist).quelle
memcmp
vorausgesetzt, der Speicher wurde zuerst gelöscht. Welches ist nah an der Arbeit, aber nicht korrekt. Natürlich definiert die Frage auch nicht "Gleichheit". Wenn Sie also "byteweise Gleichheit der Objektdarstellung" meinen, dannmemcmp
tut dies genau das (ob der Speicher gelöscht wird oder nicht).Wenn Sie viel tun, würde ich vorschlagen, eine Funktion zu schreiben, die die beiden Strukturen vergleicht. Auf diese Weise müssen Sie den Vergleich nur an einer Stelle ändern, wenn Sie jemals die Struktur ändern.
Wie es geht ... Sie müssen jedes Element einzeln vergleichen
quelle
Sie können memcmp nicht verwenden, um Strukturen auf Gleichheit zu vergleichen, da möglicherweise zufällige Auffüllzeichen zwischen Feldern in Strukturen vorhanden sind.
Das Obige würde für eine Struktur wie diese fehlschlagen:
Sie müssen einen Vergleich nach Mitgliedern verwenden, um sicher zu sein.
quelle
@ Greg ist richtig, dass man im allgemeinen Fall explizite Vergleichsfunktionen schreiben muss.
Es ist möglich zu verwenden,
memcmp
wenn:NaN
.-Wpadded
mit clang, um dies zu überprüfen) ODER die Strukturen werdenmemset
bei der Initialisierung explizit mit initialisiert.BOOL
) mit unterschiedlichen, aber äquivalenten Werten.Wenn Sie nicht für eingebettete Systeme programmieren (oder eine Bibliothek schreiben, die möglicherweise auf ihnen verwendet wird), würde ich mir keine Gedanken über einige der Eckfälle im C-Standard machen. Die Nah- und Fernzeigerunterscheidung existiert auf keinem 32- oder 64-Bit-Gerät. Kein mir bekanntes nicht eingebettetes System verfügt über mehrere
NULL
Zeiger.Eine andere Möglichkeit besteht darin, die Gleichheitsfunktionen automatisch zu generieren. Wenn Sie Ihre Strukturdefinitionen auf einfache Weise anordnen, können Sie mithilfe einfacher Textverarbeitung einfache Strukturdefinitionen verarbeiten. Sie können libclang für den allgemeinen Fall verwenden - da es dasselbe Frontend wie Clang verwendet, werden alle Eckfälle korrekt behandelt (mit Ausnahme von Fehlern).
Ich habe eine solche Codegenerierungsbibliothek nicht gesehen. Es erscheint jedoch relativ einfach.
Es ist jedoch auch der Fall, dass solche generierten Gleichheitsfunktionen auf Anwendungsebene häufig das Falsche tun.
UNICODE_STRING
Sollten beispielsweise zwei Strukturen in Windows flach oder tief verglichen werden?quelle
memset
usw. garantiert nicht den Wert der Füllbits nach dem weiteren Schreiben in ein Strukturelement, siehe: stackoverflow.com/q/52684192/689161Beachten Sie, dass Sie memcmp () für nicht statische Strukturen verwenden können, ohne sich Gedanken über das Auffüllen machen zu müssen, solange Sie nicht alle Mitglieder (auf einmal) initialisieren. Dies wird durch C90 definiert:
http://www.pixelbeat.org/programming/gcc/auto_init.html
quelle
{0, }
auch Auffüllbytes auf Null gesetzt werden?Es hängt davon ab, ob die Frage, die Sie stellen, lautet:
Um herauszufinden, ob es sich um dasselbe Objekt handelt, vergleichen Sie die Zeiger auf die beiden Strukturen, um die Gleichheit zu gewährleisten. Wenn Sie allgemein herausfinden möchten, ob sie den gleichen Wert haben, müssen Sie einen gründlichen Vergleich durchführen. Dies beinhaltet den Vergleich aller Mitglieder. Wenn die Mitglieder Zeiger auf andere Strukturen sind, müssen Sie auch in diese Strukturen zurückgreifen.
In dem speziellen Fall, in dem die Strukturen keine Zeiger enthalten, können Sie ein memcmp ausführen, um einen bitweisen Vergleich der jeweils enthaltenen Daten durchzuführen, ohne wissen zu müssen, was die Daten bedeuten.
Stellen Sie sicher, dass Sie wissen, was "gleich" für jedes Mitglied bedeutet - es ist für Ints offensichtlich, aber subtiler, wenn es um Gleitkommawerte oder benutzerdefinierte Typen geht.
quelle
memcmp
vergleicht die Struktur nicht,memcmp
vergleicht die Binärdatei und es gibt immer Müll in der Struktur, daher kommt sie im Vergleich immer als falsch heraus.Vergleichen Sie Element für Element, es ist sicher und schlägt nicht fehl.
quelle
Wenn die Strukturen nur Grundelemente enthalten oder wenn Sie an strikter Gleichheit interessiert sind, können Sie Folgendes tun:
Wenn Ihre Strukturen jedoch Zeiger auf andere Strukturen oder Vereinigungen enthalten, müssen Sie eine Funktion schreiben, die die Grundelemente ordnungsgemäß vergleicht, und gegebenenfalls Vergleichsaufrufe mit den anderen Strukturen durchführen.
Beachten Sie jedoch, dass Sie memset (& a, sizeof (struct my_struct), 1) verwendet haben sollten, um den Speicherbereich der Strukturen im Rahmen Ihrer ADT-Initialisierung auf Null zu setzen.
quelle
Wenn die Variablen mit 2 Strukturen mit calloc initialisiert werden oder mit memset auf 0 gesetzt werden, können Sie Ihre 2 Strukturen mit memcmp vergleichen, und Sie müssen sich keine Sorgen um Strukturmüll machen. Dadurch können Sie Zeit verdienen
quelle
In diesem kompatiblen Beispiel wird die Compiler-Erweiterung #pragma pack von Microsoft Visual Studio verwendet, um sicherzustellen, dass die Strukturelemente so dicht wie möglich gepackt sind:
quelle