Равенство структуры с использованием pragma pack в C

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

Но если я использую пакет #pragma (1), который удаляет свободные байты, тогда сравнение должно выполняться плавно, но оно все равно дает ошибку при сравнении.

Пример кода

#include<stdio.h>
#pragma pack(1)
struct person
{
    int uid;
    char nameStart;
};
struct personDupe
{
    int uid;
    char nameStart;
};
int main()
{
    struct person var;
    struct personDupe varDupe;
    printf("\nSize of person : %3d\n",sizeof(var));
    printf("\nSize of personDupe : %3d\n",sizeof(varDupe));

    var.uid = 12;
    var.nameStart = 'a';

    varDupe.uid = 12;
    varDupe.nameStart = 'a';

    if(var == varDupe)    //Error is introduced
        printf("\nStructures are equal\n");
    return 0;
}

person BigO    schedule 27.08.2015    source источник
comment
Какую ошибку вы получаете?   -  person Bob Jarvis - Reinstate Monica    schedule 27.08.2015
comment
Второй вопрос: почему у вас есть два отдельных типа, если вы считаете, что они равны?   -  person Bo Persson    schedule 27.08.2015
comment
@Bo Persson Второй тип предназначен только для проверки логики, возникшей у меня в голове в отношении пакета прагмы, в противном случае для проверки равенства memcmp полезен, как предложил Джек.   -  person BigO    schedule 27.08.2015
comment
@Bob Jarvis Ошибка: D:\Code\structEquality.c|26|ошибка: недопустимые операнды для двоичного кода == (имеют 'struct person' и 'struct personDupe')|   -  person BigO    schedule 27.08.2015
comment
Что такое резервный байт?   -  person too honest for this site    schedule 27.08.2015
comment
Струйная упаковка определяется реализацией. Стандарт не упоминает об этом и не гарантирует, что две структуры будут сравниваться одинаково. Вы действительно должны сравнивать по полю.   -  person too honest for this site    schedule 27.08.2015
comment
@Olaf проверьте этот вопрос: stackoverflow.com/questions/ 7300638/slack-byte-in-c-structures   -  person BigO    schedule 27.08.2015
comment
@BigO: я спрашивал, что означает термин «свободный байт». Я очень хорошо знаю о байтах заполнения для выравнивания в структурах и битов заполнения в стандартных типах. Я уже предполагал, что это может быть нечто подобное; эта фраза просто необычная (никогда ее раньше не встречала), и термин slack, кажется, не очень подходит в переводе leo.org.   -  person too honest for this site    schedule 27.08.2015
comment
@ Олаф, кстати, я получил полезный ресурс по вашей справочной ссылке.   -  person BigO    schedule 27.08.2015
comment
Да, эталон всегда под рукой.   -  person too honest for this site    schedule 27.08.2015
comment
Пожалуйста, не используйте #pragma pack, это не переносимо и вызывает всевозможные проблемы.   -  person fuz    schedule 28.08.2015


Ответы (2)


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

bool same_person(struct person* p, struct personDupe* dupe)
{ return p->uid == dupe->uid && p->nameStart == dupe->nameStart; }

И тогда вы можете сделать

if(same_person(&var, &varDupe))
    printf("\nStructures are equal\n");
person Bo Persson    schedule 27.08.2015
comment
Это нормально, но это будет раздражать большое количество элементов данных. Было бы хорошо, если бы у нас было какое-то общее решение. - person BigO; 27.08.2015
comment
@BigO C - это не язык с отражением, универсальное решение невозможно - person Vinicius Kamakura; 27.08.2015
comment
@BigO: вы можете использовать метапрограммирование для создания как структуры, так и функции сравнения из общего описания. - person too honest for this site; 27.08.2015
comment
@ Олаф, можешь привести пример? - person BigO; 27.08.2015
comment
@BigO: Пью, я некоторое время назад отвечал на вопросы о сериализации. Это аналогичная проблема. Вы можете просмотреть мои ответы, если сможете их найти. Вкратце, метапрограммирование здесь означает использование языка высокого уровня (для этого я использую Python) для генерации кода C (или его части). Вы можете использовать HLL-конструкцию для описания вашего struct, и HLL-код будет генерировать окружающий материал для определения и необходимых функций (например, копирование, сравнение и т. д.). Таким образом, вам не нужно писать все самому и сохранять все в едином виде, если вы интегрируете это в свой процесс сборки. - person too honest for this site; 27.08.2015
comment
@BigO: для сериализации есть, например, Nanopb. Сам не пользовался, но выглядит довольно многообещающе. Я думаю, что caode можно легко расширить для других целей. - person too honest for this site; 27.08.2015

Ваш код не компилируется, так как вы не можете напрямую сравнивать два struct.

Вы должны использовать что-то вроде memcmp:

memcmp(&var, &varDupe, sizeof(var));

Это не решает проблему заполнения, которую можно решить, убедившись, что структура правильно инициализирована известным значением даже в байтах заполнения (которые можно получить с помощью memset до инициализации полей).

Но подход упаковки struct для удаления отступов только для проверки их равенства кажется хрупким решением. Если компилятору требуется заполнение, то у него есть для этого веская причина, возможно, связанная с производительностью.

person Jack    schedule 27.08.2015
comment
Memcmp иногда немного небезопасен, так как вы можете иметь отступы в структуре. Я думаю, всегда безопасно сравнивать членов. Но если вы заставили не делать отступы, то с memcmp все в порядке. - person Ritesh; 27.08.2015
comment
@Ritesh: это все еще не нормально, так как у вас все еще может быть отступ в конце структуры для выравнивания элемента mext, если он используется в массиве. В C компилятор не может этого знать. - person too honest for this site; 27.08.2015