Как вы сравниваете два случая структур на равенство в стандарте C?
Как вы сравниваете два случая структур на равенство в стандарте C?
Ответы:
C не предоставляет никаких языковых возможностей для этого - вы должны сделать это сами и сравнить каждого члена структуры с каждым членом.
0.0, -0.0 NaN
проблемой memcmp()
. Указатели, которые отличаются в двоичном представлении, могут указывать на одно и то же местоположение (например, DOS: seg: offset) и, следовательно, равны. Некоторые системы имеют несколько нулевых указателей, которые сравниваются одинаково. То же самое для неясных int
типов с -0 и типов с плавающей запятой с избыточным кодированием. (Intel long double, decimal64 и т. Д.) Эти проблемы не имеют значения, calloc()
используется или нет или заполнение.
==
не работает со структурами (как я), пожалуйста , см stackoverflow.com/questions/46995631/...
Вы можете испытать желание использовать memcmp(&a, &b, sizeof(struct foo))
, но это может не работать во всех ситуациях. Компилятор может добавить буферное пространство выравнивания в структуру, и значения, найденные в ячейках памяти, лежащих в буферном пространстве, не обязательно будут каким-либо конкретным значением.
Но, если вы используете calloc
или memset
полный размер структур перед их использованием, вы можете выполнить поверхностное сравнение с memcmp
(если ваша структура содержит указатели, она будет совпадать, только если адрес, на который указывают указатели, одинаков).
memcmp
условии, что память была очищена первой. Что близко к работе, но не правильно. Конечно, вопрос также не определяет «равенство», поэтому, если вы понимаете, что это означает «побайтовое равенство представления объекта», то memcmp
именно это и делает (очищается память или нет).
Если вы делаете это много, я бы предложил написать функцию, которая сравнивает две структуры. Таким образом, если вы когда-нибудь измените структуру, вам нужно изменить сравнение только в одном месте.
Что касается того, как это сделать .... Вам нужно сравнить каждый элемент в отдельности
Вы не можете использовать memcmp для сравнения структур на равенство из-за возможных случайных символов заполнения между полями в структурах.
// bad
memcmp(&struct1, &struct2, sizeof(struct1));
Выше не получится для такой структуры:
typedef struct Foo {
char a;
/* padding */
double d;
/* padding */
char e;
/* padding */
int f;
} Foo ;
Вы должны использовать сравнение для каждого члена, чтобы быть в безопасности.
@ Грег правильно, что нужно написать явные функции сравнения в общем случае.
Можно использовать, memcmp
если:
NaN
.-Wpadded
для проверки clang) ИЛИ структуры явно инициализируются memset
при инициализации.BOOL
), которые имеют различные, но эквивалентные значения.Если вы не программируете для встраиваемых систем (или пишете библиотеку, которая может быть использована на них), я бы не стал беспокоиться о некоторых ключевых случаях в стандарте C. Различение ближнего и дальнего указателя не существует ни на одном 32- или 64-разрядном устройстве. Ни одна не встроенная система, о которой я знаю, не имеет нескольких NULL
указателей.
Другой вариант - автоматически генерировать функции равенства. Если вы выложите свои определения структуры простым способом, можно использовать простую обработку текста для обработки простых определений структуры. Вы можете использовать libclang для общего случая - поскольку он использует тот же внешний интерфейс, что и Clang, он правильно обрабатывает все угловые случаи (за исключением ошибок).
Я не видел такой библиотеки генерации кода. Однако это выглядит относительно просто.
Тем не менее, это также тот случай, когда такие сгенерированные функции равенства часто делают неправильные вещи на уровне приложения. Например, следует UNICODE_STRING
ли сравнивать две структуры в Windows поверхностно или поверхностно?
memset
и т. Д. Не гарантирует значение битов заполнения после дальнейшей записи в элемент структуры, см .: stackoverflow.com/q/52684192/689161
Обратите внимание, что вы можете использовать memcmp () для нестатических структур, не беспокоясь о заполнении, если вы не инициализируете все элементы (сразу). Это определяется C90:
{0, }
также будет обнулять любые байты заполнения?
Это зависит от того, является ли вопрос, который вы задаете:
Чтобы выяснить, являются ли они одним и тем же объектом, сравните указатели с двумя структурами равенства. Если вы хотите узнать в общем, имеют ли они одинаковое значение, вы должны сделать глубокое сравнение. Это включает в себя сравнение всех членов. Если участники являются указателями на другие структуры, вам также необходимо участвовать в этих структурах.
В особом случае, когда структуры не содержат указателей, вы можете сделать memcmp, чтобы выполнить побитовое сравнение данных, содержащихся в каждом, без необходимости знать, что эти данные означают.
Убедитесь, что вы знаете, что означает «равно» для каждого члена - это очевидно для целых чисел, но более тонко, когда речь идет о значениях с плавающей запятой или пользовательских типах.
memcmp
не сравнивает структуру, memcmp
сравнивает двоичный файл, и в структуре всегда есть мусор, поэтому он всегда выдает False в сравнении.
Сравните элемент за элементом, это безопасно и не терпит неудачу.
Если структуры содержат только примитивы или если вы заинтересованы в строгом равенстве, вы можете сделать что-то вроде этого:
int my_struct_cmp (const struct my_struct * lhs, const struct my_struct * rhs) { вернуть memcmp (lhs, rsh, sizeof (struct my_struct)); }
Однако, если ваши структуры содержат указатели на другие структуры или объединения, вам нужно написать функцию, которая правильно сравнивает примитивы и при необходимости выполняет сравнения с другими структурами.
Имейте в виду, однако, что вы должны были использовать memset (& a, sizeof (struct my_struct), 1), чтобы обнулить диапазон памяти структур как часть вашей инициализации ADT.
В этом совместимом примере используется расширение компилятора #pragma pack из Microsoft Visual Studio для обеспечения максимально плотной упаковки элементов структуры:
#include <string.h>
#pragma pack(push, 1)
struct s {
char c;
int i;
char buffer[13];
};
#pragma pack(pop)
void compare(const struct s *left, const struct s *right) {
if (0 == memcmp(left, right, sizeof(struct s))) {
/* ... */
}
}