سؤال

If I have two C structures initialised to have identical members, can I guarantee that:

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

will always return zero?

هل كانت مفيدة؟

المحلول

I don't think you can safely memcmp a structure to test for equality.

From C11 §6.2.6.6 Representations of types

When a value is stored in an object of structure or union type, including in a member object, the bytes of the object representation that correspond to any padding bytes take unspecified values.

This implies that you'd need to write a function which compares individual elements of the structure

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;
}

نصائح أخرى

No, two structures with all members equal may sometimes not compare equal for memcmp(), because of padding.

One plausible example is as follows. For the initialization of st2, a standard-compliant 32-bit compiler could generate a sequence of assembly instructions that leave part of the final padding uninitialized. This piece of padding will contain whatever happened to be there on the stack, whereas st1's padding will typically contain zero:

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
}

If both variables are global or static, and their members were initialized at init time of the program, then yes, they will compare equal with memcmp(). (Note, most systems just load the data pages into zero initialized pages, but the C standard does not guarantee this behavior.)

Also, if one of the structures were initialized with the other using memcpy(), then they will compare equal with memcmp().

If both were initialized to some common value with memset() first before their members are initialized to the same values, then they will also compare equal with memcmp() (unless their members are also structures, then the same restrictions apply recursively).

Beside the obvious case of struct padding, it is not even guaranteed for single variables. See the footnote for 6.2.6.1 (8):

It is possible for objects x and y with the same effective type T to have the same value when they are accessed as objects of type T, but to have different values in other contexts. In particular, if == is defined for type T, then x == y does not imply that memcmp(&x, &y, sizeof (T)) == 0. Furthermore, x == y does not necessarily imply that x and y have the same value; other operations on values of type T may distinguish between them.

You can guarantee that they're identical if you ensure that both entire memory blocks are initialised before they're populated, e.g. with memset:

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

EDIT leaving this here because the comment stream is useful.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top