comparing structs

Hi,

Is there an easy way to test if two instances of the same struct contain the same data? Something along the lines of:

struct Inputs {
  int input_01;
  int input_02;
  int input_03;
  int input_04;

};

Inputs intput1 = {1,2,3,4};
Inputs inputt2 = {5,6,7,8};

bool compare = (input1 == input2);

Or must I iterate through the members of the struct?

Thanks!

You must compare member by member.

You could abstract the process by overloading 'operator=='.

1 Like

memcmp.

Given the names you picked for the struct attributes, an array would seem more appropriate (and memcmp would still be the way to go)

J-M-L:
Given the names you picked for the struct attributes, an array would seem more appropriate (and memcmp would still be the way to go)

Plan is to use it for more than just ints, this is just a test example

Ok then struct (/a class with methods or overloading == operator) is the way to go especially if your struct is not shallow (if you have pointers to other non constant places / objects in memory in it then memcmp() won’t work)

Overloading == will let you burry the details of the comparison in the class and you could then just do if (struct1 == struct2) {...}

To my knowledge C and C++ don't have low-level operations on composite data types, neither
structs, classes nor arrays, it all has to be element by element.

This is why memcpy() is popular!

MarkT:
This is why memcpy() is popular!

As already noted, that will fail if the struct is not "Shallow".

The problem with memcpy memcmp is that it compares the raw byte representation of an object, not the actual values of the object.

As others have mentioned, it will fail when the struct is not shallow, i.e. if it contains pointers, or if it contains any other members that contain pointers.

It will also fail if any of the members has a user-defined comarison operator (==).

For example, if any of the members of a sturct are const char *, String, float, etc., you cannot use memcmp. Meaningful comparison of two const char * strings requires strcmp, not just a comparison of the pointers. String contains a pointer to the actual string on the heap, so it's not shallow and requires a user-defined comparison operator. Floating point values can be equal (or not equal), even if their raw bit patterns are different (or the same), e.g. NaN != NaN and +0 == -0.

However, there's a much more serious problem: compilers are free to add padding bytes between members of a struct, and these padding bytes have indeterminate values. Therefore, comparing two structures with padding invokes undefined behavior (or implementation defined behavior?), because you have no guarantee that the padding bytes will be the same, even if all members are the same.

From cppreference:

This function reads object representations, not the object values, and is typically meaningful for byte arrays only: structs may have padding bytes whose values are indeterminate, the values of any bytes beyond the last stored member in a union are indeterminate, and a type may have two or more representations for the same value (different encodings for +0 and -0 or for +0.0 and –0.0, indeterminate padding bits within the type).

In conclusion, only use memcmp to compare raw byte representations, use operator== if you want to compare the values of two objects.

Overloading operator== and operator!= can be done as follows:

struct Inputs {
  int input_01;
  int input_02;
  int input_03;
  int input_04;

  bool operator==(const Inputs &other) const {
    return this->input_01 == other.input_01
        && this->input_02 == other.input_02
        && this->input_03 == other.input_03
        && this->input_04 == other.input_04;
  }
  bool operator!=(const Inputs &other) const {
    return !(*this == other);
  }
};

Pieter

1 Like

Thanks for the answers! I will try the overloading technique.

Hi Pieter,
Thanks for the struct comparison code, I definitely learned something there! Unfortunately, I didn't really understand what you have done, so I asked the friend who taught me C; for the benefit of anyone else who needs an explanation here is what he told me:

if (a == b) …

This (circled in red) – left hand operand (a). 'this' just means the current instance. Don't worry about it for now if you don't understand it.

Pink – members of instance a

other (circled in blue) – right hand operand (b). You can think of this like calling a function and passing a parameter. b is the parameter passed. other is the variable name within the function.

Cyan – members of instance b

Green – data type for right hand operand.

Good sample code indeed.

ÉDIT: nonsense below

As a side note the overloading of the operator != is suboptimal when written this way

bool operator!=(const Inputs &other) const {
    return !(*this == other);
  }

if it were written like the first one (with || and !=) it would evaluate faster as it will stop the comparisons as soon as one is true (in the same way == will stop as soon as one is false)

PieterP:
The problem with memcpy is that it compares the raw byte representation of an object, not the actual values of the object.

memcpy does not compare anything, it simply does a blind copy. Perhaps you meant memcmp?

Regards,
Ray L.

MarkT:
This is why memcpy() is popular!

Same here - indeed they intended to say memcmp() of course

J-M-L:
As a side note the overloading of the operator != is suboptimal when written this way

bool operator!=(const Inputs &other) const {

return !(*this == other);
  }


if it were written like the first one (with || and !=) it would evaluate faster as it will stop the comparisons as soon as one is true (in the same way == will stop as soon as one is false)

I don't believe that's the case. If the two objects are the same, operator!= has to check all four members to be sure.
If the objects are different, the && in operator== will short circuit on the first member that differs and return early, so operator!= also returns early. It doesn't matter if you use || and != or && and ==.

RayLivingston:
memcpy does not compare anything, it simply does a blind copy. Perhaps you meant memcmp?

Thanks, should be fixed now.

PieterP:
I don't believe that's the case.

You are completely right indeed ! In Boolean logic

!(A & B & C & D) is the same as (!A | !B | !C | !D)

Writing the two functions saves you just the Boolean inversion which is peanuts - makes sense to write it the way you did indeed