c - comparing two structure

xox

Joined Sep 8, 2017
936
Like this? :)
[...]
Output:
different
Neat trick but just skirts initialization best practices. You're always supposed to initialize structures directly (otherwise use a function, like memset).

Code:
#include <string.h>
#include <stdio.h>
#pragma packed
typedef union
{
    struct
    {
        unsigned a:1; unsigned b:1; unsigned c:1; unsigned d:1; unsigned e:1; unsigned f:1; unsigned g:1; unsigned h:1; unsigned i:1; unsigned j:1; unsigned k:1;
        unsigned Reserved:22;
    } MyBits;
    unsigned int FourBytes;
} MyUnion;
int main(int argc, char* argv[])
{
  MyUnion c1 = {0};
  MyUnion c2 = {0};
  if (memcmp(&c1, &c2, sizeof(MyUnion)) == 0)
  {
    printf("same\n");
  }
  else
  {
    printf("different\n");
  }
  return 0;
}

//    Output: "same"
See? Problem solved. And memcmp is perfectly okay in certain contexts too. Others times you'll be making a different kind of comparison anyway (like which employee has accrued the most overtime, or whatever). But it isn't going to break your system to use it. Being forced to maintain code instead of relying on automation...yeah...have fun with that!
 

MrSoftware

Joined Oct 29, 2013
2,273
I forgot to add in my code, you're safest to pack your structs tightly so the compiler doesn't add any padding, such as:

Code:
#pragma pack(1)
union
{
    struct
    {
        Uint16 Bit1:1;
        Uint16 Bit2:1;
        Uint16 Reserved:14;  /* Must be 0 */
    }MyBits;
    Uint16 TwoBytes;
}MyUnion;
--- OR ---

Code:
#pragma pack(push, 1)
union
{
    struct
    {
        Uint16 Bit1:1;
        Uint16 Bit2:1;
        Uint16 Reserved:14;  /* Must be 0 */
    }MyBits;
    Uint16 TwoBytes;
}MyUnion;

#pragma pack(pop)
 

miniwinwm

Joined Feb 2, 2018
68
I forgot to add in my code, you're safest to pack your structs tightly so the compiler doesn't add any padding
A problem with pragma pack, even pragma pack(1), is that it's not always guaranteed not to still have some padding. While this...

Code:
#pragma pack(1)
struct s
{
  char a;
  int b;
  char c;
};
is almost certainly going to be unpadded, this is not...

Code:
#pragma pack(1)
struct s
{
  unsigned a:30;
  unsigned b:4;
  unsigned c:30;
};
Even though the total number of bits is a multiple of a word size for a 32 bit processor, bitfields cannot cross word boundaries, so this struct will be spread across 3 words, not 2.

This kind of behaviour, which may not be known or obvious to everyone, either now or some unknown time in the future during maintenance, is why memcmp of structures is not allowed by the coding standards for safety critical code. Member by member comparison of fields is tedious and long winded, requires all the fun of careful and rigorous implementation, reviewing and testing, but is understood by everyone and doesn't rely on remembering to initialise the struct to zero. Shortcuts might be ok for student projects, but not for landing planes or administering drugs. The guiding philosophy in SC code now is KISS.
 

xox

Joined Sep 8, 2017
936
This kind of behaviour, which may not be known or obvious to everyone, either now or some unknown time in the future during maintenance, is why memcmp of structures is not allowed by the coding standards for safety critical code. Member by member comparison of fields is tedious and long winded, requires all the fun of careful and rigorous implementation, reviewing and testing, but is understood by everyone and doesn't rely on remembering to initialise the struct to zero. Shortcuts might be ok for student projects, but not for landing planes or administering drugs. The guiding philosophy in SC code now is KISS.
I've never once encountered a project imposing this silly restriction. Produce a program that requires member-by-member comparison. Otherwise please stop spouting such misleading nonsense!
 

MrSoftware

Joined Oct 29, 2013
2,273
I'm sure someome must have done it, but I've never personally worked in code where bitfields crossed boundaries. I would say it's a bad idea, don't do it, and you should be OK. Pack everything and make sure every bit is explicitly defined.
 

miniwinwm

Joined Feb 2, 2018
68
I'm sure someome must have done it, but I've never personally worked in code where bitfields crossed boundaries. I would say it's a bad idea, don't do it, and you should be OK. Pack everything and make sure every bit is explicitly defined.
Yes, of course, my examples of 30 bit bitfields crossing a word boundary are just that, examples, & unrealistic. However, they do show that specifying packing does not guarantee it.

Where it can happen inadvertently is where an extra bit is added to a bitfield but the user added padding field is not decremented. This is the kind of easily overlooked bug that can cause nasty occasional failures when combined with a union in or memcmp of a struct.
 

MrSoftware

Joined Oct 29, 2013
2,273
To play devils advocate, that would be similar risk to adding a bit field but neglecting to add the new compare. You can guard against your suggested issue by:

ASSERT(sizeof(MyUnion) == ExpectedSizeBytes);

You'll know immediately if the union grew from someone adding a bit.
 
Top