How to compare structures for equality in C?

This blog post explains the best way to compare two structures (same type) for equality. You will learn from this blog post How to compare structs for equality in C.

 

The following topic we will cover in this blog post:

  • How to compare structs for equality in C?
  • Why can’t you compare two structs using the (==) equality operator?
  • Is safe to use memcmp() for structure equality comparison?

 

Safe way to compare two structures objects?

The safe way to compare the equality of the structure is to explicitly compare the structure member by member.

Consider the below examples,

Case 1: Both objects have the same value

#include <stdio.h>

struct Test
{
    int a;
    char b;
};

int main()
{
    struct Test obj1, obj2;

    /*Assigning value to the obj1*/
    obj1.a = 1;
    obj1.b = 2;

    /*Assigning value to the obj2*/
    obj2.a = 1;
    obj2.b = 2;

    //Comparing the objects of structure
    if((obj1.a == obj2.a) && (obj1.b == obj2.b))
    {
        printf("Struct objects are equal\n");
    }

    return 0;
}

Output: Struct objects are equal

 

Case 2: Both objects don’t have the same value:

#include <stdio.h>

struct Test
{
    int a;
    char b;
};

int main()
{
    struct Test obj1, obj2;

    /*Assigning value to the obj1*/
    obj1.a = 10;
    obj1.b = 2;

    /*Assigning value to the obj2*/
    obj2.a = 1;
    obj2.b = 2;

    //Comparing the objects of structure
    if((obj1.a == obj2.a) && (obj1.b == obj2.b))
    {
        printf("Struct objects are equal\n");
    }
    else
    {
        printf("Struct objects are Not equal\n");
    }

    return 0;
}

Output: Struct objects are Not equal

 

You can also write a small compare function and simply call this function whenever required to check the equality of the objects of the same structure type.

#include <stdio.h>
#include <stdbool.h>

struct Test
{
    int a;
    char b;
};

bool isEqual(struct Test const * const pObj1, struct Test const * const pObj2)
{
    return ((pObj1->a == pObj2->a) && (pObj1->b == pObj2->b));
}

int main()
{
    struct Test obj1, obj2;

    /*Assigning value to the obj1*/
    obj1.a = 1;
    obj1.b = 2;

    /*Assigning value to the obj2*/
    obj2.a = 1;
    obj2.b = 2;

    //Comparing the objects of structure
    if(isEqual(&obj1,&obj2))
    {
        printf("Struct objects are equal\n");
    }
    else
    {
        printf("Struct objects are Not equal\n");
    }

    return 0;
}

 

In the above example code, you can see I have created a function isEqual() for comparison of the structure objects. I have used bool in C as a return type which is supported by the C language since C99. If you are working on an old compiler you can use int.

Only one problem with function implementation is that every time you need to update the function with respect to the structure members.

For example, if I add a third member ‘c’ to the ‘struct Test‘ and forget to update the function;  The behavior of the function will not be according to their implementation. That means you will get the wrong output.

#include <stdio.h>
#include <stdbool.h>

struct Test
{
    int a;
    char b;
    int c;
};

bool isEqual(struct Test const * const pObj1, struct Test const * const pObj2)
{
    return ((pObj1->a == pObj2->a) && (pObj1->b == pObj2->b));
}

int main()
{
    struct Test obj1, obj2;

    /*Assigning value to the obj1*/
    obj1.a = 1;
    obj1.b = 2;
    obj1.c = 3;
    /*Assigning value to the obj2*/
    obj2.a = 1;
    obj2.b = 2;
    obj2.c = 4; //<

Output: Struct objects are equal

Function isEqual() is not updated according to the structure that is getting the wrong output. After updating the function you will get the actual result see the below example code.

#include <stdio.h>
#include <stdbool.h>

struct Test
{
    int a;
    char b;
    int c;
};

bool isEqual(struct Test const * const pObj1, struct Test const * const pObj2)
{
    return ((pObj1->a == pObj2->a) && (pObj1->b == pObj2->b) && (pObj1->c == pObj2->c));
}

int main()
{
    struct Test obj1, obj2;
    /*Assigning value to the obj1*/
    obj1.a = 1;
    obj1.b = 2;
    obj1.c = 3;
    /*Assigning value to the obj2*/
    obj2.a = 1;
    obj2.b = 2;
    obj2.c = 4;
    //Comparing the objects of structure
    if(isEqual(&obj1,&obj2))
    {
        printf("Struct objects are equal\n");
    }
    else
    {
        printf("Struct objects are Not equal\n");
    }
    return 0;
}

Output: Struct objects are Not equal

 

 

UnSafe way to compare two structures objects?

Comparing the structures using memcmp() is not safe. I am saying this because your structure may have padding bytes containing unspecified values. This unspecified value could be different for both structures objects.

The memcmp() function compares the object of both structures byte by bye which means it also compares the padding bytes. Because the value of the padding bytes unspecified so you will not get the actual result.

Let’s take an example for a better understanding. Consider a plain 32-bit two’s complement system with no trap representations.

#include <stdio.h>
#include <string.h>
#include <stdint.h>

typedef struct
{
    uint8_t  a;
    uint32_t b;
} plainStruct;


int main()
{
    //object 1
    plainStruct obj1 = {10, 12};
    //object 2
    plainStruct obj2 = {10, 12};

    if(memcmp(&obj1,&obj2, sizeof(plainStruct)) != 0)
    {
        printf("They are not equal\n");
    }
    else
    {
        printf("They are equal\n");
    }

    return 0;
}

In the above example, I have created two local objects of a structure and assigned the same value to their members. But still, it is not sure which part of the code will execute if part or else part.

Now you are thinking why I am saying this; the reason is the padding bytes. The C standard does not define the value of the padding bytes. They said that “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”.

Consider the below example memory layout of the obj1 and obj2(hex, little-endian):

0A 34 78 32     0C 00 00 00  // obj1
0A 34 AA CC     0C 00 00 00  // obj2
^  ^            ^
a  padding      b

where in obj1, the member 'a' has the value 01, the 34 78 32 sequence is padding bytes with unspecified values and 0C000000 is the value of the member 'b'.

In obj2, the value of 'a'and 'b' are the same but because the value of padding is unspecified which is right now 34 AA CC.

That is the reason why I am saying that you should not use the memcmp function to compare the variables of a structure.

 

✌ Bonus Knowledge for you:

A structure assignment need not copy any padding bits which means if you write obj1 = obj2, the compiler is not bounded to copy the padding bytes from the obj2 to obj1 and they can leave the padding bytes of obj1 as it is.

//object 1
plainStruct obj1 = {10, 12};


//object 2
plainStruct obj2 = obj1;

 

But it also might be possible that the compiler allowed to copy the whole obj1 and overwrite all of obj2, including padding bytes.

 

Recommended Post:

Leave a Reply

Your email address will not be published. Required fields are marked *