Comparing structs...

B

barcaroller

Is it legal to compare the contents of two multi-field variables (of the
same struct) using "==" and "!="?

struct
{
int a;
int b;
} x,y;

...

if (x==y) // ?


Or is there a chance that the compiler may, for whatever reason, use
different layouts/paddings for the two variables even though they are of the
same struct?
 
K

Keith Thompson

barcaroller said:
Is it legal to compare the contents of two multi-field variables (of the
same struct) using "==" and "!="?

struct
{
int a;
int b;
} x,y;

...

if (x==y) // ?

No, the "==" and "!=" operators are not defined for structs.
(Assignment is, though.)
Or is there a chance that the compiler may, for whatever reason, use
different layouts/paddings for the two variables even though they are of the
same struct?

The layout is determined by the type, so that's guaranteed to be the
same. Specifically, the size and offset of a and b, and the size of
the entire struct, is the same for x as it is for y. This would be
a bit clearer if you gave the struct type a name:

struct foo {
int a;
int b;
};

struct foo x, y;

You can use memcmp() to determine whether two objects have the same
representation (this examines all the bits), but the compiler is free
to insert padding between members or after the last one, and the
contents of the padding can be garbage.

The only real way to compare x and y is to compare each member
explicitly:

x.a == y.a && x.b == y.b
 
M

Mark

No, the "==" and "!=" operators are not defined for structs.
(Assignment is, though.)

Just curious: why? (Is assignment defined but not == an !=.)

It would think that if you are capable of copying one object to an other
you should also be capable of comparing them?

Regards,
Mark.
 
A

A. Sinan Unur

Just curious: why? (Is assignment defined but not == an !=.)

It would think that if you are capable of copying one object to an other
you should also be capable of comparing them?

I don't claim to know what the actual rationale is but the following
argument for not specifiying how structs should be compared makes sense to
me.

Comparison is not well defined. For example, if the struct has pointer
members, does equality mean equality of pointers, or equality of values
pointed to by those pointers.

Or, are all fields relevant for the comparison?

Sinan
 
C

Chris Torek

Just curious: why? (Is assignment defined but not == an !=.)

It would, I think, have been reasonable[%] for Standard C to have
defined both equality and relational operators for "struct"s,
using the "obvious" definition that:

s1 comparison_op s2

would "mean":

s1.field1 comparison_op s2.field1 &&
s1.field2 comparison_op s2.field2 &&
...
s1.fieldN comparison_op s2.fieldN

Note, however, that in the general case -- using relational operators,
or using equality operators on structures that contain padding --
this would compile to many instructions on most machines. On most
systems today, the ordinary assignment operators compile to just
a few instructions: either an inlined memcpy(), or an actual call
to memcpy(), in most cases.

For a concrete example:

struct big { int n; char c; unsigned short j; double v[1000]; };

struct big v1, v2;
...
v1 = v2;

generally compiles to the equivalent of "memcpy(&v1, &v2, sizeof v1)",
while under this proposal, even:

v1 == v2

would compile to at least two separate comparisons, and probably
at least four: one for v1.n vs v2.n, one for v1.c vs v2.c, and for
v1.j vs v2.j, and perhaps one call to a support library loop for
v1.v vs v2.v. (Note that NaN != NaN but +0.0 == -0.0, so simple
bitwise comparisons will fail for "double"s. So while the first
three comparisons might actually be doable with memcmp(), provided
there is no padding between "c" and "j", the last one cannot.)

[% Or at least not totally *un*reasonable.]
 
K

Keith Thompson

A. Sinan Unur said:
I don't claim to know what the actual rationale is but the following
argument for not specifiying how structs should be compared makes sense to
me.

Comparison is not well defined. For example, if the struct has pointer
members, does equality mean equality of pointers, or equality of values
pointed to by those pointers.

Or, are all fields relevant for the comparison?

I don't think it would make sense to follow pointer members, any more
than "==" on pointers should compare the objects they point to.

There are two plausible ways to define structure comparison. One
would be equivalent to memcmp(), but that would cause problems with
padding bytes. Defining it apply "==" to each member (and each
recursively to members of members) makes sense (<OT>Ada does
this</OT>), but it requires the compiler to generate considerable code
for (x == y), which is generally considered to be against the "spirit
of C".

If you want to compare structures, you can write a function to do the
comparison (though it might be more convenient if the compiler did it
for you). And if you write it yourself, you can allow for cases where
you *don't* want to compare all the members:

struct my_string {
size_t len;
char str[MAX];
};

or where you want to follow pointers:

struct my_string {
size_t len;
char *str;
};
 
C

code break

but the compiler is freeto insert padding between members or after the
last one..

Then How we can prevent the padding from compiler...
 
E

Eric Sosman

A. Sinan Unur said:
@tiscali.nl:

Just curious: why? (Is assignment defined but not == an !=.)

It would think that if you are capable of copying one object to an other
you should also be capable of comparing them?


I don't claim to know what the actual rationale is [...]

Fortunately, the committee that wrote the Standard also
wrote (... wait for it ...) the Rationale! 6.5.9:

"The C89 Committee considered, on more than one occasion,
permitting comparison of structures for equality. Such
proposals foundered on the problem of holes in structures.
A byte-wise comparison of two structures would require
that the holes assuredly be set to zero so that all holes
would compare equal, a difficult task for automatic or
dynamically allocated variables. The possibility of union-
type elements in a structure raises insuperable problems
with this approach. Without the assurance that all holes
were set to zero, the implementation would have to be
prepared to break a structure comparison into an arbitrary
number of member comparisons; a seemingly simple expression
could thus expand into a substantial stretch of code, which
is contrary to the spirit of C."
 
M

Mark

A. Sinan Unur said:
@tiscali.nl:

On Wed, 29 Mar 2006 01:30:55 +0000, Keith Thompson wrote:


No, the "==" and "!=" operators are not defined for structs.
(Assignment is, though.)


Just curious: why? (Is assignment defined but not == an !=.)

It would think that if you are capable of copying one object to an other
you should also be capable of comparing them?


I don't claim to know what the actual rationale is [...]

Fortunately, the committee that wrote the Standard also
wrote (... wait for it ...) the Rationale! 6.5.9:

"The C89 Committee considered, on more than one occasion,
permitting comparison of structures for equality. Such
proposals foundered on the problem of holes in structures.
A byte-wise comparison of two structures would require
that the holes assuredly be set to zero so that all holes
would compare equal, a difficult task for automatic or
dynamically allocated variables. The possibility of union-
type elements in a structure raises insuperable problems
with this approach. Without the assurance that all holes
were set to zero, the implementation would have to be
prepared to break a structure comparison into an arbitrary
number of member comparisons; a seemingly simple expression
could thus expand into a substantial stretch of code, which
is contrary to the spirit of C."

But ofcource!! the padding, why didn't I think of that?! :)

Thanks, everyone, for the answer.

Regards,
Mark,
 
J

Jordan Abel

I don't think it would make sense to follow pointer members, any more
than "==" on pointers should compare the objects they point to.

There are two plausible ways to define structure comparison. One
would be equivalent to memcmp(), but that would cause problems with
padding bytes. Defining it apply "==" to each member (and each
recursively to members of members) makes sense (<OT>Ada does
this</OT>), but it requires the compiler to generate considerable code
for (x == y), which is generally considered to be against the "spirit
of C".

A compiler could use memcmp and ensure that all padding bits/bytes are
always equal to zero.

It doesn't take considerable code to use "=" on a struct, or to pass or
return it? returning structs was once very messy.
 
K

Keith Thompson

Jordan Abel said:
A compiler could use memcmp and ensure that all padding bits/bytes are
always equal to zero.

How could it ensure that all padding is always zero? Consider structs
allocated by malloc(). Consider structs read from a file (which
introduces portability problems anyway, but at least it works when the
same program writes and reads the same file).

Also consider members that are unions, floating-point members that
might be NaNs, and pointer members on an implementation where pointer
equality can't be done as a bitwise comparison.

Even if all this were worked out, the resulting "==" operator wouldn't
necessarily correspond to what the user wants to do. And how often do
you really want to compare structures for equality anyway?

All these things could have been resolved, but I agree with the
committee that it wasn't worthwhile.
It doesn't take considerable code to use "=" on a struct, or to pass or
return it? returning structs was once very messy.

It's not nearly as messy as "==" would be -- and considerably more
useful.

There's always a tradeoff in deciding whether to add a feature to the
language, and it can always be argued that the decision should have
been made differently.
 
M

Mark McIntyre

How could it ensure that all padding is always zero? Consider structs
allocated by malloc().

There are several ways this could be done, but they'd impose a
significant performance penalty. For instance the compiler could
insist that all struct padding bits are set to zero when a struct is
created, or it could copy the struct before comparison, find and zero
any padding bits, then do the compare.
Also consider members that are unions, floating-point members that
might be NaNs, and pointer members on an implementation where pointer
equality can't be done as a bitwise comparison.

These are rather more significant issues, I suspect.

Mark McIntyre
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,176
Messages
2,570,947
Members
47,501
Latest member
Ledmyplace

Latest Threads

Top