Reputation: 22329
How do you compare two instances of structs for equality in standard C?
Upvotes: 263
Views: 283034
Reputation: 1
A somewhat useful; but slow method is as follows:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#define GENERATE_COMPARE(s) int compare_##s(s a, s b) {\
s _a, _b; \
bzero(&_a, sizeof(s)); \
bzero(&_b, sizeof(s)); \
_a = a; _b = b; \
return bcmp(&_a,&_b,sizeof(s)); \
}
typedef struct foo { int a,b; } foo_t;
GENERATE_COMPARE(foo_t);
int main(int xc, char **ac) {
foo_t a = { 1, 2 };
foo_t b = { 2, 3 };
foo_t c = { 1, 2 };
if (compare_foo_t(a,b)) {
printf("A and B are not equal\n");
} else {
printf("A and B are equal\n");
};
assert(0 != compare_foo_t(a,b));
assert(0 != compare_foo_t(b,a));
assert(0 != compare_foo_t(b,a));
assert(0 != compare_foo_t(c,b));
assert(0 == compare_foo_t(c,a));
assert(0 == compare_foo_t(a,c));
}
This bypasses the issues of (non)packed structs by nulling two temporary sections of memory; copying the struct to there; and then compare.
Upvotes: -1
Reputation: 2086
For many cases on embedded systems, structs are frequently used for their bitfield capability in particular. A good (safe) option in this case is to union your struct anonymously with a fixed-width type whose equality operator is well defined.
You can try this example in your browser:
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
// Given the struct you want to compare:
//
// | typedef struct {
// | uint8_t a : 1;
// | uint16_t b : 9;
// | uint8_t c : 3;
// | uint8_t _ : 2;
// | uint8_t d : 1;
// | } data;
//
// Embed it anonymously in a union:
typedef union {
uint16_t u16;
struct {
uint8_t a : 1;
uint16_t b : 9;
uint8_t c : 3;
uint8_t _ : 2;
uint8_t d : 1;
};
} data;
// Code that previously referred to members of struct data:
//
// | data d; // struct
// | d.a = 0; // immediate field a of d.
//
// Can continue using identical syntax without change:
//
// | data d; // union
// | d.a = 0; // nested field a of anonymous struct in d.
// Return 0 if a == b, -1 if a < b, +1 if a > b.
int data_cmp(const void *a, const void *b);
int main(int argc, char *argv[]) {
data d[] = {
{ .a = 1, .b = 300, .c = 4, .d = 0 },
{ .a = 1, .b = 300, .c = 4, .d = 0 },
{ .a = 0, .b = 300, .c = 4, .d = 0 },
{ .a = 1, .b = 500, .c = 2, .d = 0 },
};
size_t n = sizeof(d) / sizeof(*d);
// You can use any comparison operator on the value unioned
// with your struct.
if (d[0].u16 == d[1].u16) {
// You can also make use of ordinary library functions.
qsort(d, n, sizeof(data), data_cmp);
}
// When not testing for equality (e.g., sorting), be aware of
// byte ordering!
for (size_t i = 0; i < n; ++i) {
printf("d[%d]: { %d, %d, %d, %d }\n",
i, d[i].a, d[i].b, d[i].c, d[i].d);
}
}
int data_cmp(const void *a, const void *b) {
return ((const data *)a)->u16 - ((const data *)b)->u16;
}
Upvotes: -1
Reputation: 330
Question is related to C, not gcc.
The fact is that several C compilers exists, and not all of them are nearly adherent to the standards. And also, several different architectures exists around, with different mem alignments for structures.
To compare the structs, those should be at least "pragma packed", and properly zero-initialized.
But as said above multiple times, better to compare their members as needed.
Upvotes: 0
Reputation: 3611
@Greg is correct that one must write explicit comparison functions in the general case.
It is possible to use memcmp
if:
NaN
.-Wpadded
with clang to check this) OR the structs are explicitly initialized with memset
at initialization.BOOL
) that have distinct but equivalent values.Unless you are programming for embedded systems (or writing a library that might be used on them), I would not worry about some of the corner cases in the C standard. The near vs. far pointer distinction does not exist on any 32- or 64- bit device. No non-embedded system that I know of has multiple NULL
pointers.
Another option is to auto-generate the equality functions. If you lay your struct definitions out in a simple way, it is possible to use simple text processing to handle simple struct definitions. You can use libclang for the general case – since it uses the same frontend as Clang, it handles all corner cases correctly (barring bugs).
I have not seen such a code generation library. However, it appears relatively simple.
However, it is also the case that such generated equality functions would often do the wrong thing at application level. For example, should two UNICODE_STRING
structs in Windows be compared shallowly or deeply?
Upvotes: 10
Reputation: 8755
You may be tempted to use memcmp(&a, &b, sizeof(struct foo))
, but it may not work in all situations. The compiler may add alignment buffer space to a structure, and the values found at memory locations lying in the buffer space are not guaranteed to be any particular value.
But, if you use calloc
or memset
the full size of the structures before using them, you can do a shallow comparison with memcmp
(if your structure contains pointers, it will match only if the address the pointers are pointing to are the same).
Upvotes: 136
Reputation: 2542
This compliant example uses the #pragma pack compiler extension from Microsoft Visual Studio to ensure the structure members are packed as tightly as possible:
#include <string.h>
#pragma pack(push, 1)
struct s {
char c;
int i;
char buffer[13];
};
#pragma pack(pop)
void compare(const struct s *left, const struct s *right) {
if (0 == memcmp(left, right, sizeof(struct s))) {
/* ... */
}
}
Upvotes: -3
Reputation: 43578
if the 2 structures variable are initialied with calloc or they are set with 0 by memset so you can compare your 2 structures with memcmp and there is no worry about structure garbage and this will allow you to earn time
Upvotes: -3
Reputation: 427
memcmp
does not compare structure, memcmp
compares the binary, and there is always garbage in the struct, therefore it always comes out False in comparison.
Compare element by element its safe and doesn't fail.
Upvotes: 1
Reputation: 5100
It depends on whether the question you are asking is:
To find out if they are the same object, compare pointers to the two structs for equality. If you want to find out in general if they have the same value you have to do a deep comparison. This involves comparing all the members. If the members are pointers to other structs you need to recurse into those structs too.
In the special case where the structs do not contain pointers you can do a memcmp to perform a bitwise comparison of the data contained in each without having to know what the data means.
Make sure you know what 'equals' means for each member - it is obvious for ints but more subtle when it comes to floating-point values or user-defined types.
Upvotes: 2
Reputation: 31768
Note you can use memcmp() on non static stuctures without worrying about padding, as long as you don't initialise all members (at once). This is defined by C90:
http://www.pixelbeat.org/programming/gcc/auto_init.html
Upvotes: 3
Reputation: 891
If the structs only contain primitives or if you are interested in strict equality then you can do something like this:
int my_struct_cmp(const struct my_struct * lhs, const struct my_struct * rhs) { return memcmp(lhs, rsh, sizeof(struct my_struct)); }
However, if your structs contain pointers to other structs or unions then you will need to write a function that compares the primitives properly and make comparison calls against the other structures as appropriate.
Be aware, however, that you should have used memset(&a, sizeof(struct my_struct), 1) to zero out the memory range of the structures as part of your ADT initialization.
Upvotes: -1
Reputation:
You can't use memcmp to compare structs for equality due to potential random padding characters between field in structs.
// bad
memcmp(&struct1, &struct2, sizeof(struct1));
The above would fail for a struct like this:
typedef struct Foo {
char a;
/* padding */
double d;
/* padding */
char e;
/* padding */
int f;
} Foo ;
You have to use member-wise comparison to be safe.
Upvotes: 23
Reputation: 2801
If you do it a lot I would suggest writing a function that compares the two structures. That way, if you ever change the structure you only need to change the compare in one place.
As for how to do it.... You need to compare every element individually
Upvotes: 25
Reputation: 994371
C provides no language facilities to do this - you have to do it yourself and compare each structure member by member.
Upvotes: 243