Почему C не обеспечивает сравнение структур? - PullRequest
14 голосов
/ 24 августа 2011

Как известно большинству программистов на С, нельзя сравнивать две структуры напрямую.

Рассмотрим:

void isequal(MY_STRUCT a, MY_STRUCT b)
{
    if (a == b)
    {
        puts("equal");
    }
    else
    {
        puts("not equal");
    }
 }

Сравнение a==b заставит AFAIK вызвать ошибку компиляции на любом разумном компиляторе C, потому что стандарт C не допускает сравнение встроенных структур. Обходные пути с использованием memcmp, конечно, плохая идея из-за выравнивания, упаковки, битовых полей и т. Д., Поэтому мы в конечном итоге пишем элемент с помощью функций сравнения элементов.

С другой стороны, он допускает присвоение структуры, например, a = b полностью законно. Очевидно, что компилятор может справиться с этим довольно тривиально, так почему бы не сравнить?

Единственная идея, которая у меня была, заключалась в том, что присвоение структуры, вероятно, довольно близко к memcpy (), так как пробелы из-за выравнивания и т. Д. Не имеют значения. С другой стороны, сравнение может быть более сложным. Или мне этого не хватает?

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

Ответы [ 5 ]

9 голосов
/ 05 ноября 2014

Как уже упоминалось, вот выдержка из C: Справочное руководство от Harbison and Steele:

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

9 голосов
/ 24 августа 2011

Сравнение не поддерживается по той же причине memcmp не удается.

Из-за полей заполнения сравнение может быть непредсказуемым, что будет неприемлемым для большинства программистов. Присвоение изменяет невидимые поля заполнения, но в любом случае они невидимы, поэтому ничего неожиданного там нет.

Очевидно, вы можете спросить: так почему бы просто не заполнить нулями все поля заполнения? Конечно, это сработает, но это также заставит все программы платить за то, что им может не понадобиться.

EDIT

Оли Чарлсворт отмечает в комментариях, которые вы можете спросить: «почему компилятор не генерирует код для сравнения между членами». Если это так, я должен признаться: Я не знаю :-). Компилятор будет иметь всю необходимую информацию, если только позволит сравнивать полные типы.

6 голосов
/ 01 ноября 2017

Я нашел это в обосновании ( обоснование C99 V5.10 ), 6.5.9:

Комитет С89 неоднократно рассматривал возможность сравненияструктур для равенства.Такие предложения основывались на проблеме дыр в конструкциях.Побайтовое сравнение двух структур потребовало бы, чтобы отверстия были обязательно установлены на ноль, чтобы все отверстия сравнивались одинаково, трудная задача для автоматических или динамически назначаемых переменных.

Возможность элементов типа объединения вструктура поднимает непреодолимые проблемы с этим подходом.Без уверенности в том, что все дыры были установлены на ноль, реализация должна была бы быть готова разбить сравнение структур на произвольное число сравнений элементов;таким образом, казалось бы, простое выражение могло бы расшириться до значительной части кода, что противоречит духу C

На простом английском языке: поскольку структуры / союзы могут содержать байты заполнения, а комитет не применялони содержат определенные значения, они не будут реализовывать эту функцию.Потому что, если все байты заполнения должны быть установлены в ноль, это потребует дополнительных накладных расходов во время выполнения.

4 голосов
/ 24 августа 2011

Оператор сравнения с автоматической генерацией - плохая идея.Представьте себе, как сравнение будет работать для этой структуры:

struct s1 {
   int len;
   char str[100];
};

Это строка, похожая на паскаль, с максимальной длиной 100

Другой случай

struct s2 {
   char a[100];
}

Как компилятор может узнать, каксравнить поле?Если это строка, оканчивающаяся NUL, компилятор должен использовать strcmp или strncmp.Если это компилятор массива char должен использовать memcmp.

1 голос
/ 17 января 2018

Чтобы добавить к существующим хорошим ответам:

struct foo {
    union {
        uint32_t i;
        float f;
    } u;
} a, b;
a.u.f = -0.0;
b.u.f = 0.0;
if (a==b) // what to do?!

Проблема возникает из-за того, что профсоюзы не могут сохранить / отследить, какой член является текущим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...