Как вы сравниваете структуры для равенства в C?

Как вы сравниваете два экземпляра структур для равенства в стандарте C?

Ответы

Ответ 1

C не предоставляет языковых возможностей для этого - вам нужно сделать это самостоятельно и сравнить каждый член структуры по члену.

Ответ 2

У вас может возникнуть соблазн использовать memcmp(&a, &b, sizeof(struct foo)), но он может не работать во всех ситуациях. Компилятор может добавить буферное пространство выравнивания к структуре, а значения, найденные в ячейках памяти, лежащих в буферном пространстве, не гарантируются каким-либо конкретным значением.

Но если вы используете calloc или memset полный размер структур перед их использованием, вы можете выполнить мелкое сравнение с memcmp (если ваша структура содержит указатели, это будет соответствовать только в том случае, если адрес, на который указывают указатели, одинаковый).

Ответ 3

Если вы это сделаете, я бы предложил написать функцию, которая сравнивает две структуры. Таким образом, если вы когда-либо меняете структуру, вам нужно только изменить сравнение в одном месте.

Как это сделать... Вам нужно сравнить каждый элемент отдельно

Ответ 4

Вы не можете использовать memcmp для сравнения структур для равенства из-за потенциального случайного заполнения символов между полями в структурах.

  // bad
  memcmp(&struct1, &struct2, sizeof(struct1));

Вышеупомянутое не получилось бы для такой структуры:

typedef struct Foo {
  char a;
  /* padding */
  double d;
  /* padding */
  char e;
  /* padding */
  int f;
} Foo ;

Вы должны использовать сравнение по элементам, чтобы быть в безопасности.

Ответ 5

Обратите внимание, что вы можете использовать memcmp() для нестационарных структур без беспокоясь о заполнении, если вы не инициализируете всех участников (сразу). Это определяется C90:

http://www.pixelbeat.org/programming/gcc/auto_init.html

Ответ 6

@Greg корректен, что в общем случае нужно писать явные функции сравнения.

Можно использовать memcmp, если:

  • структуры не содержат полей с плавающей запятой, возможно, NaN.
  • в структурах нет отступов (используйте -Wpadded с clang, чтобы проверить это) ИЛИ структуры инициализируются с инициализацией memset.
  • нет типов членов (таких как Windows BOOL), которые имеют разные, но эквивалентные значения.

Если вы не программируете встроенные системы (или записываете библиотеку, которая может быть использована на них), я бы не стал беспокоиться о некоторых из угловых случаев в стандарте C. Различие между соседними и удаленными указателями не существует ни на одном 32- или 64-битном устройстве. Нет встроенной системы, о которой я знаю, имеет несколько указателей NULL.

Другой вариант - автоматическое создание функций равенства. Если вы легко определяете определения структуры, можно использовать простую текстовую обработку для обработки простых описаний структур. Вы можете использовать libclang для общего случая – поскольку он использует тот же интерфейс, что и Clang, он корректно обрабатывает все угловые регистры (запрещает ошибки).

Я не видел такую ​​библиотеку генерации кода. Однако он выглядит относительно простым.

Однако также случается, что такие сгенерированные функции равенства часто поступают неправильно на уровне приложения.

Ответ 7

memcmp не сравнивает структуру, memcmp сравнивает двоичный файл, и в структуре всегда есть мусор, поэтому он всегда встречается с False в сравнении.

Сравнить элемент за элементом безопасно и не прерывается.

Ответ 8

Если структуры содержат только примитивы или если вас интересует строгое равенство, вы можете сделать что-то вроде этого:

int my_struct_cmp(const struct my_struct * lhs, const struct my_struct * rhs)
{
    return memcmp(lhs, rsh, sizeof(struct my_struct));
}

Однако, если ваши структуры содержат указатели на другие структуры или объединения, вам нужно будет написать функцию, которая правильно сравнивает примитивы и сопоставляет вызовы сопоставления с другими структурами по мере необходимости.

Помните, однако, что вы должны использовать memset (& a, sizeof (struct my_struct), 1), чтобы обнулить диапазон памяти структур как часть вашей инициализации ADT.

Ответ 9

Это зависит от того, задается ли вопрос:

  • Являются ли эти две структуры одним и тем же объектом?
  • У них одинаковое значение?

Чтобы узнать, являются ли они одним и тем же объектом, сравните указатели с двумя структурами для равенства. Если вы хотите узнать вообще, если они имеют одинаковое значение, вам нужно сделать глубокое сравнение. Это предполагает сравнение всех членов. Если члены являются указателями на другие структуры, вам также нужно перечислить эти структуры.

В частном случае, когда структуры не содержат указателей, вы можете сделать memcmp для выполнения поразрядного сравнения данных, содержащихся в каждом, не зная, что означают данные.

Убедитесь, что вы знаете, что означает "equals" для каждого члена - это очевидно для ints, но более тонкое, когда речь идет о значениях с плавающей запятой или пользовательских типах.

Ответ 10

если переменная 2 структур инициализируется calloc или они установлены с помощью 0 memset, поэтому вы можете сравнить свои 2 структуры с memcmp и не беспокоиться о структуре мусора, и это позволит вам зарабатывать время

Ответ 11

Этот совместимый пример использует расширение компилятора пакета #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))) {
    /* ... */
  }
}