By Hans Sjunnesson


2008-09-26 20:21:23 8 Comments

How do you compare two instances of structs for equality in standard C?

11 comments

@Demi 2015-08-19 05:39:21

@Greg is correct that one must write explicit comparison functions in the general case.

It is possible to use memcmp if:

  • the structs contain no floating-point fields that are possibly NaN.
  • the structs contain no padding (use -Wpadded with clang to check this) OR the structs are explicitly initialized with memset at initialization.
  • there are no member types (such as Windows 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?

@gengkev 2018-10-11 14:15:59

Explicitly initializing the structs with memset, etc. does not guarantee the value of the padding bits after further writing to a struct element, see: stackoverflow.com/q/52684192/689161

@Sufian 2008-09-26 20:32:39

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).

@Steve Jessop 2008-09-26 22:43:11

Close, because it works on "almost all" compilers, but not quite. Check out 6.2.1.6.4 in C90: "Two values (other than NaNs) with the same object representation compare equal, but values that compare equal may have different object representations."

@Samuel 2013-02-08 15:18:04

What? Can anyone explain Steve's quotation?

@ajs410 2013-04-16 03:41:34

Consider a "BOOL" field. In terms of equality, any non-zero BOOL is equal to every non-zero BOOL value. So while 1 and 2 may both be TRUE and therefore equal, memcmp will fail.

@Samuel 2013-06-24 22:48:37

Thanks ajs. This is a good point that Steve makes.

@bunkerdive 2013-11-05 23:45:18

Note that for many systems, there are usually compiler qualifiers, such as __packed (two underscores, e.g. typedef __packed struct) that will prevent the compiler from adding alignment padding. This makes things much easier

@Mecki 2014-03-31 22:48:58

@JSalazar Easier for you maybe, but much harder for the compiler and the CPU and thus also much slower. Why do you think compiler add padding in the first place? Certainly not to waste memory for nothing ;)

@Demi 2015-08-19 05:38:32

@SteveJessop Do you know of any (non-embedded) system where this actually happens?

@Steve Jessop 2015-08-19 13:35:23

@Demetri: for example the float values positive and negative zero compare equal on any IEEE float implementation, but they do not have the same object representation. So actually I should not have said it works on "almost all compilers", it will fail on any implementation that lets you store a negative zero. I was probably thinking of funny integer representations at the time I made the comment.

@Demi 2015-08-19 14:01:44

@SteveJessop true, but many structs do not contain floats.

@Steve Jessop 2015-08-20 12:12:55

@Demetri: but many do contain floats, and the questioner asks "how do you compare structs", not "how do you compare structs that don't contain floats". This answer says you can do a shallow compare with memcmp provided that the memory was cleared first. Which is close to working but not correct. Ofc the question also doesn't define "equality", so if you take it to mean "byte-wise equality of the object representation" then memcmp does exactly that (whether the memory is cleared or not).

@autistic 2015-12-11 02:31:14

It's worth noting that a standard-compliant C compiler may not add padding to the beginning of a struct; only after members... and if a struct X contains the same initial sequence of elements as a struct Y then those elements are required to exist at the same offsets.

@Antimony 2016-07-12 02:52:53

Also note that from a pedantic perspective, two objects with the same type and binary representation can still have different behavior in certain cases. I don't think any real world compiler takes advantage of this though.

@eat_a_lemon 2017-05-29 15:07:58

if the structs contains pointers and each one is allocated with two different malloc calls then the pointer addresses will be different between the two structs and memcmp will fail. There needs to be a mechanism that compares by value regardless of the type of the struct member

@gengkev 2018-10-11 14:14:02

Initializing the struct with memset, etc is not enough to ensure the padding bits are still the same after writing to members of the struct, see: stackoverflow.com/q/52684192/689161

@Hesham Eraqi 2014-09-30 17:06:41

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))) {
    /* ... */
  }
}

@Ruud Althuizen 2015-04-10 07:31:09

That is indeed correct. But in most cases you do not want your structs to be packed! Quite a lot of instructions, and pointers, require that the input data is word-aligned. If it's not, then the compiler needs to add extra instructions to copy and re-align data before the actual instruction can be executed. If the compiler would not re-align the data the CPU will throw an exception.

@MOHAMED 2012-10-03 09:11:00

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

@sergio 2012-08-07 19:15:47

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.

@MOHAMED 2012-10-03 09:08:28

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

@domgblackwell 2008-09-27 14:41:58

It depends on whether the question you are asking is:

  1. Are these two structs the same object?
  2. Do they have the same value?

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.

@pixelbeat 2008-09-26 20:52:38

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

@Alnitak 2015-12-04 16:21:13

Is it actually specified that {0, } will also zero any padding bytes?

@pixelbeat 2015-12-05 17:26:31

GCC at least zeroes padding bytes for partially initialized structs as demonstrated at the link above, and stackoverflow.com/questions/13056364/… details that C11 specifies that behavior.

@M.M 2017-10-29 01:20:24

Not very useful in general, because all padding becomes indeterminate upon assigning to any member

@Kevin S. 2008-09-26 20:34:40

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.

@structinator 2008-09-26 20:34:12

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.

@Jonathan Leffler 2008-09-27 05:41:13

Unlikely to be padding after the double; the char will be perfectly adequately aligned immediately after the double.

@Ben 2008-09-26 20:24:32

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

@Sam 2018-11-08 09:32:10

I would write a separate function even if I were to use it only once.

@Greg Hewgill 2008-09-26 20:22:14

C provides no language facilities to do this - you have to do it yourself and compare each structure member by member.

@MOHAMED 2012-10-03 09:09:49

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

@chux 2015-04-14 15:02:53

@MOHAMED Comparing floating point fields with 0.0, -0.0 NaN is a problem with memcmp(). Pointers that differ in binary representation may point to the same location (e.g. DOS: seg:offset) and so are equal. Some systems have multiple null pointers which compare equally. Same for obscure int with -0 and floating point types with redundant encodings. (Intel long double, decimal64, etc.) These issues make no difference is calloc() used or not or padding.

@Demi 2017-09-21 00:11:26

@chux On any modern 32- or 64- bit system I know of, the only issue is with floating point.

@stefanct 2017-10-28 23:57:09

In case you wonder why == is not working with structures (like me), please see stackoverflow.com/questions/46995631/…

@Martin Bonner 2017-12-21 17:11:20

@Demi : Today. The 10th commandment for C programmers is 'Thou shalt foreswear, renounce, and abjure the vile heresy which claimeth that “All the world’s a VAX” ... '. Replacing this with "All the world's a PC" is not an improvement.

@Demi 2017-12-23 19:14:13

@MartinBonner Can you name a specific system that is still in use on which memcmp will not work, provided that the struct has neither padding (use -Wpadded to check this) or floating-point values?

@Martin Bonner 2017-12-23 19:46:45

@Demi No. But they have existed, and may again

@Igor Stoppa 2018-12-25 15:37:59

If structure B is a copy of structure A, obtained through memcpy(), then it should be ok to compare them with memcmp(), because in both cases they are treated as binary objects. As long as B is not altered in any way, before the comparison. Even B = B should be avoided.

Related Questions

Sponsored Content

10 Answered Questions

[SOLVED] Improve INSERT-per-second performance of SQLite?

8 Answered Questions

[SOLVED] Compare object instances for equality by their attributes in Python

  • 2009-08-04 12:09:38
  • Željko Živković
  • 168865 View
  • 196 Score
  • 8 Answer
  • Tags:   python equality

28 Answered Questions

[SOLVED] When to use struct?

  • 2009-02-06 17:37:55
  • Alex Baranosky
  • 245522 View
  • 1296 Score
  • 28 Answer
  • Tags:   c# struct

24 Answered Questions

[SOLVED] When should you use a class vs a struct in C++?

  • 2008-09-10 16:29:54
  • Alan Hinchcliffe
  • 356246 View
  • 827 Score
  • 24 Answer
  • Tags:   c++ oop class struct ooad

26 Answered Questions

[SOLVED] How do you set, clear, and toggle a single bit?

14 Answered Questions

20 Answered Questions

[SOLVED] Is there a difference between "==" and "is"?

12 Answered Questions

[SOLVED] typedef struct vs struct definitions

  • 2009-11-04 17:21:57
  • user69514
  • 599803 View
  • 703 Score
  • 12 Answer
  • Tags:   c struct typedef

11 Answered Questions

[SOLVED] Why isn't sizeof for a struct equal to the sum of sizeof of each member?

Sponsored Content