tags:

views:

396

answers:

1

Even though I am a long time C programmer, I only recently learned that one can directly assign structure variables to one another instead of using memcpy:

struct MyStruct a,b;
...
a = b; /* implicit memcpy */

Though this feels a bit "high-level" for C, it is definitely useful. But why can't I do equality and inequality comparison:

if (a == b) ...
if (a != b) ...

Is there any good reason for the standard to exclude this? Or is this an inconsistency in the - otherwise very elegant - standard?

I don't see why I can replace my memcpy's for clean assignments, but I have to keep those ugly memcmp's in place.

+18  A: 

Per the comp.lang.c FAQ:

There is no good way for a compiler to implement structure comparison (i.e. to support the == operator for structures) which is consistent with C's low-level flavor. A simple byte-by-byte comparison could founder on random bits present in unused "holes" in the structure (such padding is used to keep the alignment of later fields correct). A field-by-field comparison might require unacceptable amounts of repetitive code for large structures. Any compiler-generated comparison could not be expected to compare pointer fields appropriately in all cases: for example, it's often appropriate to compare char * fields with strcmp rather than ==.

If you need to compare two structures, you'll have to write your own function to do so, field by field.

Jonathan Feinberg
I knew there was a good reason for it. I just forgot about the holes in structures.
Chris Lutz
Thanks. I understand the padding argument. But doesn't the pointer-field argument hold equally well for assignment?
Tomas
@Tomas No, it's really quite common to have multiple pointers to a single object. Consider a tree, with extra pointers from each child to its parent.
Andres Jaan Tack
presumably memcmp would fail for the same reason, right?
MeThinks
What about C++ does the compiler generate hole-initializing code and a correct == operator behind the scenes ?. I mention this because the mutable keyword is present and AFAIK its purpose is to aid simple default == operator member functions.
Hassan Syed
@MeThinks Good point. This seems to mean that I can't do a memcmp after a=b because I can't be sure about padding. Although a compiler would be pretty silly if it would skip padding on assigment...
Tomas
@Self: This does make the use of structure assignment limited. It seems I should stick to memcpy in most cases..
Tomas
The padding argument makes sense, but the pointer comparison bit seems pretty bogus. Yes, you'd probably want to define your own comparison function for structs containing pointers to strings, but the same is true for stand-alone pointers. ie: you probably want to use strcmp rather than == for comparison.
Laurence Gonsalves
"a compiler would be pretty silly if it would skip padding on assigment...". Not necessarily. For instance if there's padding at the end, I think the compiler can skip it on assignment. Assuming it's legal, there's no point copying it. But because you've carefully written platform-independent code, you don't know there's padding at the end, so your memcmp would be for `sizeof(struct MyStruct)` bytes, and include the padding which didn't get copied.
Steve Jessop
@Hassan: in C++ the compiler generates assignment code (unless you tell it not to), which might be quite lengthy. The difference is that C++ is higher level, and you expect the code to be out-of-line when there are complex objects involved. C++ doesn't generate comparison operators though. You have to do it yourself, so it's your call whether to include mutable data members or not.
Steve Jessop
You might also consider what happens when you have unions in the struct. Unions are easy to copy, but hard to compare. A field-by-field compare of elements would be wasteful, of course, but size/padding differences between the elements mean that you can't just compare any one element. It becomes very tricky to determine which bytes are padding and which are relevant.
Casey Barker