Jak porównać dwa przypadki struktur dla równości w standardowym C?
216
C nie udostępnia żadnych narzędzi językowych, aby to zrobić - musisz to zrobić sam i porównać każdego członka struktury według członka.
0.0, -0.0 NaN
jest problem zmemcmp()
. Wskaźniki, które różnią się reprezentacją binarną, mogą wskazywać na tę samą lokalizację (np. DOS: seg: offset), a więc są równe. Niektóre systemy mają wiele zerowych wskaźników, które porównują się jednakowo. To samo dotyczy niejasnychint
typów -0 i zmiennoprzecinkowych z kodowaniem redundantnym. (Intel long double, decimal64 itp.) Te problemy nie mającalloc()
znaczenia, czy są używane, czy nie, ani padding.==
nie działa ze strukturami (jak ja), zobacz stackoverflow.com/questions/46995631/...Możesz ulec pokusie użycia
memcmp(&a, &b, sizeof(struct foo))
, ale może nie działać we wszystkich sytuacjach. Kompilator może dodawać przestrzeń bufora wyrównania do struktury, a wartości znalezione w lokalizacjach pamięci znajdujących się w przestrzeni bufora nie są gwarantowane, że będą jakąś szczególną wartością.Ale jeśli używasz
calloc
lubmemset
pełny rozmiar struktur przed ich użyciem, to może zrobić płytkie porównanie zmemcmp
(jeśli struktura zawiera wskaźniki, będzie pasować tylko wtedy, gdy adres Wskaźniki wskazują na to samo).źródło
memcmp
warunkiem, że pamięć została najpierw wyczyszczona. Co jest bliskie pracy, ale nie jest poprawne. Często pytanie również nie definiuje „równości”, więc jeśli przyjmiesz, że oznacza to „bajtową równość reprezentacji obiektu”, tomemcmp
robi dokładnie to (niezależnie od tego, czy pamięć jest wyczyszczona, czy nie).Jeśli często to robisz, sugerowałbym napisanie funkcji porównującej dwie struktury. W ten sposób, jeśli kiedykolwiek zmienisz strukturę, wystarczy zmienić porównanie w jednym miejscu.
Co do tego, jak to zrobić ... Musisz porównać każdy element indywidualnie
źródło
Nie można używać memcmp do porównywania struktur dla równości ze względu na potencjalne losowe wypełnianie znaków między polami w strukturach.
Powyższe nie powiedzie się dla struktury takiej jak ta:
Aby być bezpiecznym, musisz użyć porównania członków.
źródło
@Greg ma rację, że w ogólnym przypadku należy napisać wyraźne funkcje porównawcze.
Można użyć,
memcmp
jeśli:NaN
.-Wpadded
z clang, aby to sprawdzić) LUB struktury są jawnie inicjowanememset
przy inicjalizacji.BOOL
), które mają odrębne, ale równoważne wartości.O ile nie programujesz dla systemów wbudowanych (lub piszesz bibliotekę, która może być na nich użyta), nie martwiłbym się niektórymi przypadkami narożnymi w standardzie C. Rozróżnienie wskaźnika bliskiego i dalekiego nie istnieje na żadnym urządzeniu 32- lub 64-bitowym. Żaden znany mi system niewbudowany nie ma wielu
NULL
wskaźników.Inną opcją jest automatyczne generowanie funkcji równości. Jeśli rozłożysz definicje struktur w prosty sposób, możliwe jest użycie prostego przetwarzania tekstu do obsługi prostych definicji struktur. Możesz użyć libclang do ogólnego przypadku - ponieważ używa tej samej nakładki co Clang, poprawnie obsługuje wszystkie przypadki narożne (z wyjątkiem błędów).
Nie widziałem takiej biblioteki do generowania kodu. Wydaje się jednak stosunkowo prosty.
Jednak zdarza się również, że takie generowane funkcje równości często robią coś złego na poziomie aplikacji. Na przykład, czy dwie
UNICODE_STRING
struktury w systemie Windows powinny być porównywane płytko czy głęboko?źródło
memset
itp. Nie gwarantuje wartości bitów dopełniających po dalszym zapisywaniu do elementu struct, patrz: stackoverflow.com/q/52684192/689161Pamiętaj, że możesz używać memcmp () na statycznych konstrukcjach bez obawy o wypełnianie, o ile nie zainicjujesz wszystkich elementów (jednocześnie). Jest to zdefiniowane przez C90:
http://www.pixelbeat.org/programming/gcc/auto_init.html
źródło
{0, }
wyzeruje również bajty wypełniania?Zależy to od tego, czy zadajesz pytanie:
Aby dowiedzieć się, czy są to ten sam obiekt, porównaj wskaźniki do dwóch struktur zapewniających równość. Jeśli chcesz dowiedzieć się ogólnie, czy mają taką samą wartość, musisz dokonać głębokiego porównania. Polega to na porównaniu wszystkich członków. Jeśli członkowie są wskaźnikami do innych struktur, musisz również powrócić do tych struktur.
W szczególnym przypadku, gdy struktury nie zawierają wskaźników, możesz wykonać memcmp, aby wykonać bitowe porównanie danych zawartych w każdym z nich bez konieczności poznania znaczenia danych.
Upewnij się, że wiesz, co oznacza „równa się” dla każdego elementu członkowskiego - jest to oczywiste dla liczb całkowitych, ale bardziej subtelne, jeśli chodzi o wartości zmiennoprzecinkowe lub typy zdefiniowane przez użytkownika.
źródło
memcmp
nie porównuje struktury,memcmp
porównuje plik binarny, a struktura zawsze zawiera śmieci, dlatego zawsze wychodzi Fałsz w porównaniu.Porównaj element po elemencie, jest bezpieczny i nie zawiedzie.
źródło
Jeśli struktury zawierają tylko prymitywy lub jeśli jesteś zainteresowany ścisłą równością, możesz zrobić coś takiego:
Jeśli jednak twoje struktury zawierają wskaźniki do innych struktur lub związków, będziesz musiał napisać funkcję, która odpowiednio porównuje prymitywy i odpowiednio wywoła porównania z innymi strukturami.
Pamiętaj jednak, że powinieneś był użyć memset (& a, sizeof (struct my_struct), 1), aby wyzerować zakres pamięci struktur w ramach inicjalizacji ADT.
źródło
jeśli zmienna 2 struktury została zainicjowana za pomocą calloc lub jest ustawiona na 0 przez memset, możesz więc porównać swoje 2 struktury z memcmp i nie martw się o śmieci struktur, a to pozwoli ci zarobić czas
źródło
W tym zgodnym przykładzie użyto rozszerzenia kompilatora pakietu #pragma z Microsoft Visual Studio, aby zapewnić możliwie ścisłe spakowanie elementów struktury:
źródło