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

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

вопрос задан 26.09.2008
Hans Sjunnesson
10359 репутация

11 ответов


  • 165 рейтинг

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

    ответ дан Greg Hewgill, с репутацией 645957, 26.09.2008
  • 95 рейтинг

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

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

    ответ дан Sufian, с репутацией 6314, 26.09.2008
  • 19 рейтинг

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

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

    ответ дан Ben, с репутацией 1354, 26.09.2008
  • 17 рейтинг

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

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

    Выше не удалось бы для структуры, как это:

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

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

    ответ дан Sufian, с репутацией 6314, 26.09.2008
  • 5 рейтинг

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

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

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

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

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

    Я не видел такой библиотеки генерации кода. Однако это выглядит относительно просто.

    Однако, это также тот случай, когда такие сгенерированные функции равенства часто делают неправильные вещи на уровне приложения. Например, следует ли сравнивать две структуры UNICODE_STRING в Windows поверхностно или неглубоко?

    ответ дан Demi, с репутацией 1788, 19.08.2015
  • 5 рейтинг

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

    http: // www. pixelbeat. орг / программирование / ССАГПЗ / auto_init. HTML

    ответ дан pixelbeat, с репутацией 22496, 26.09.2008
  • 2 рейтинг

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

    Сравните элемент за элементом его безопасно и не терпит неудачу.

    ответ дан sergio, с репутацией 159, 7.08.2012
  • 1 рейтинг

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

    1. Являются ли эти две структуры одним и тем же объектом?
    2. Они имеют одинаковое значение?

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

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

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

    ответ дан domgblackwell, с репутацией 4306, 27.09.2008
  • 1 рейтинг

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

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

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

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

    ответ дан Kevin S., с репутацией 772, 26.09.2008
  • -1 рейтинг

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

    ответ дан MOHAMED, с репутацией 19506, 3.10.2012
  • -2 рейтинг

    В этом совместимом примере используется расширение компилятора #pragma pack из Microsoft Visual Studio для обеспечения максимально плотной упаковки элементов структуры:

    #include 
    
    #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))) {
        /* ... */
      }
    }
    
    ответ дан Hesham Eraqi, с репутацией 1138, 30.09.2014