Внутренняя согласованность структур C

Если у меня есть две структуры C, инициализированные одинаковыми членами, могу ли я гарантировать, что:

memcmp(&struct1, &struct2, sizeof(my_struct))

всегда будет возвращать нуль?

Ответ 1

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

Из C11 §6.2.6.6 Представления типов

Когда значение хранится в объекте структуры или типа объединения, в том числе в объекте-члене, байты представления объекта которые соответствуют любым байтам заполнения, принимают неопределенные значения.

Это означает, что вам нужно будет написать функцию, которая сравнивает отдельные элементы структуры

int my_struct_equals(my_struct* s1, my_struct* s2)
{
    if (s1->intval == s2->intval &&
        strcmp(s1->strval, s2->strval) == 0 && 
        s1->binlen == s2->binlen &&
        memcmp(s1->binval, s2->binval, s1->binlen) == 0 &&
        ...
        ) {
        return 1;
    }
    return 0;
}

Ответ 2

Нет, две структуры со всеми равными членами могут иногда не сравнивать равные для memcmp(), из-за padding.

Один из правдоподобных примеров заключается в следующем. Для инициализации st2 32-разрядный компилятор, соответствующий стандарту, может генерировать последовательность инструкций по сборке, которые оставляют часть окончательного дополнения неинициализированной. Эта часть дополнения будет содержать все, что попадало в стек, в то время как st1 заполнение обычно содержит ноль:

struct S { short s1; long long i; short s2; } st1 = { 1, 2, 3 };
int main() {
  struct S st2 = { 1, 2, 3 };
  ... at this point memcmp(&st1, &st2, sizeof(struct S)) could plausibly be nonzero
}

Ответ 3

Если обе переменные являются глобальными или статическими, а их члены были инициализированы во время инициализации программы, то да, они будут сравнивать равные с memcmp(). (Примечание. Большинство систем просто загружают страниц данных на нулевые инициализированные страницы, но стандарт C не гарантирует этого.)

Кроме того, если одна из структур была инициализирована другой с помощью memcpy(), то они будут сравнивать равные с memcmp().

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

Ответ 4

Помимо очевидного случая заполнения структуры, он даже не гарантируется для отдельных переменных. См. Сноску 6.2.6.1 (8):

Объекты x и y возможны с тем же эффективным типом T иметь одинаковое значение, когда к ним обращаются как объекты типа T, но иметь разные значения в других контекстах. В частности, если == определяется для типа T, то x == y не означает, что memcmp(&x, &y, sizeof (T)) == 0. Кроме того, x == y не обязательно следует, что x и y имеют одинаковое значение; Другие операции над значениями типа T могут различать их.

Ответ 5

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

memset(&struct1, 0, sizeof(my_struct))

EDIT, оставив это здесь, потому что поток комментариев полезен.