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?
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 (Note, most systems just load the data pages into zero initialized pages, but the C standard does not guarantee this behavior.)memcmp()
.
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
andy
with the same effective typeT
to have the same value when they are accessed as objects of typeT
, but to have different values in other contexts. In particular, if==
is defined for typeT
, thenx == y
does not imply thatmemcmp(&x, &y, sizeof (T)) == 0
. Furthermore,x == y
does not necessarily imply thatx
andy
have the same value; other operations on values of typeT
may distinguish between them.
x=y=1.0/0
they compare as unequal, x!=y
, but have memcmp(&x,&y,sizeof(double))==0
. –
Seam 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.
memcpy()
. –
Traceetracer memcpy()
ing the whole blob –
Fernandina char
to be more than 8 bits, so I don't believe such a system would be implemented that way. –
Traceetracer a = b
) or only target a specific member (a.foo = 42
), which is what the part including in a member object refers to –
Fernandina char*
, memcpy()
, ...), padding bytes should retain their values –
Fernandina © 2022 - 2024 — McMap. All rights reserved.