Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Rationale for struct assignment and no struct comparison

Reply
Thread Tools

Rationale for struct assignment and no struct comparison

 
 
Noob
Guest
Posts: n/a
 
      12-08-2009
Hello,

I don't understand why assignment of structs is supported,
but comparison is not. It seems to me that the two operations
would be of similar complexity, no?

struct foo { int i; };
int main(void)
{
struct foo s1, s2;
s1.i = 42;
s2 = s1; /* OK */
if (s1 == s2) return 0; /* syntax error */
return 0;
}

$ gcc -Wall -Wextra -std=c89 -pedantic temp.c
temp.c: In function 'main':
temp.c:7: error: invalid operands to binary == (have 'struct foo' and 'struct foo')

What was the rationale for allowing assignment and not comparison?

Assignment might be implemented via memcpy, comparison via memcmp
(although padding may cause major headache).

Regards.
 
Reply With Quote
 
 
 
 
Noob
Guest
Posts: n/a
 
      12-08-2009
Noob wrote:

> I don't understand why assignment of structs is supported,
> but comparison is not. It seems to me that the two operations
> would be of similar complexity, no?
>
> struct foo { int i; };
> int main(void)
> {
> struct foo s1, s2;
> s1.i = 42;
> s2 = s1; /* OK */
> if (s1 == s2) return 0; /* syntax error */
> return 0;
> }
>
> $ gcc -Wall -Wextra -std=c89 -pedantic temp.c
> temp.c: In function 'main':
> temp.c:7: error: invalid operands to binary == (have 'struct foo' and 'struct foo')
>
> What was the rationale for allowing assignment and not comparison?
>
> Assignment might be implemented via memcpy, comparison via memcmp
> (although padding may cause major headache).


Additional question:
After an assignment s2=s1;
is s2 bit-for-bit identical to s1
or does the padding have unspecified values?

Regards.
 
Reply With Quote
 
 
 
 
gwowen
Guest
Posts: n/a
 
      12-08-2009
On Dec 8, 4:41*pm, Noob <r...@127.0.0.1> wrote:
> I don't understand why assignment of structs is supported,
> but comparison is not.


....

> (although padding may cause major headache).


Actually, you do understand
 
Reply With Quote
 
gwowen
Guest
Posts: n/a
 
      12-08-2009
On Dec 8, 4:49*pm, Noob <r...@127.0.0.1> wrote:

> Additional question:
> After an assignment s2=s1;
> is s2 bit-for-bit identical to s1


In reality, almost certainly yes. But you can't rely on it.
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      12-08-2009
Noob <root@127.0.0.1> writes:
> I don't understand why assignment of structs is supported,
> but comparison is not. It seems to me that the two operations
> would be of similar complexity, no?
>

[...]
>
> What was the rationale for allowing assignment and not comparison?
>
> Assignment might be implemented via memcpy, comparison via memcmp
> (although padding may cause major headache).


Assignment can be implemented via (the equivalent of) memcpy.
For small structures, it can be even easier than that; the code for
a structure the same size as int might be implemented by the same
code as an int assignment, likely a single instruction. (Or the
compiler can generate code to copy each member, ignoring padding,
if there's some reason to do so.)

For comparison, yes, padding is a big problem. You can easily have
two structure objects all of whose members are equal, but which are
not bitwise identical. Furthermore, bitwise comparison might not
work for floating-point or pointer members. And defining the meaning
of equality for a structure type with a member that's a union would
be another fun task (you could say that the first declared member of
the union is compared, but it's not clear that that would be useful).

And consider something like this:

struct flex_array {
size_t len;
double data[MAX];
};

How is the compiler to know that only the first len elements of
the data array are meaningful? And what about the struct hack or
flexible array members?

Struct equality comparison *could* have been defined rigorously,
but it would have been a lot of work with a number of special cases,
the generated code could be large and inefficient, and the result
likely wouldn't match the kind of comparison *you* want to do with
*your* struct type.

--
Keith Thompson (The_Other_Keith) http://www.velocityreviews.com/forums/(E-Mail Removed) <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      12-08-2009
Noob <root@127.0.0.1> writes:

> I don't understand why assignment of structs is supported,
> but comparison is not. It seems to me that the two operations
> would be of similar complexity, no?
>
> struct foo { int i; };
> int main(void)
> {
> struct foo s1, s2;
> s1.i = 42;
> s2 = s1; /* OK */
> if (s1 == s2) return 0; /* syntax error */
> return 0;
> }
>
> $ gcc -Wall -Wextra -std=c89 -pedantic temp.c
> temp.c: In function 'main':
> temp.c:7: error: invalid operands to binary == (have 'struct foo' and 'struct foo')
>
> What was the rationale for allowing assignment and not comparison?
>
> Assignment might be implemented via memcpy, comparison via memcmp
> (although padding may cause major headache).


I think you've answered your own question! Ether s1 == s2 can be
permitted to have odd results if two otherwise identical structs have
different bits in the padding bytes (or, indeed, in the padding bits
within the values) or s1 == s2 has to turn into a whole big chunk of
code.

If you favour the first, well, memcmp is not hard to write. If you
favour the second, I suspect it is seen as contrary to the spirit of C
for a small, apparently innocent, operation to turn into a possibly
huge block of machine code.

--
Ben.
 
Reply With Quote
 
Eric Sosman
Guest
Posts: n/a
 
      12-08-2009
Noob wrote:
> Hello,
>
> I don't understand why assignment of structs is supported,
> but comparison is not. It seems to me that the two operations
> would be of similar complexity, no?


You're exactly right: "No." From the Rationale:

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.

--
Eric Sosman
(E-Mail Removed)lid
 
Reply With Quote
 
bartc
Guest
Posts: n/a
 
      12-08-2009

"Eric Sosman" <(E-Mail Removed)> wrote in message
news:hfm3nb$25p$(E-Mail Removed)-september.org...
> Noob wrote:
>> Hello,
>>
>> I don't understand why assignment of structs is supported,
>> but comparison is not. It seems to me that the two operations
>> would be of similar complexity, no?

>
> You're exactly right: "No." From the Rationale:
>
> 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.


Interesting. I developed a pretty much parallel language to C in the 1980's.

That /did/ have struct compares, and it seemed work!

However, my structs didn't have 'holes', as I knew nothing about C's method
of automatic padding (I did this manually as needed.)

Even with holes, I can imagine various schemes to compare two structs that
would not require an arbitrarily large amount of code (such as looping
through a bitmap showing the bytes that need to match, or finding out
exactly what the difficulty is in making sure padding bytes are zero) .

> The possibility of union-type elements in
> a structure raises insuperable problems with this
> approach.


How would you compare two union values anyway? Unless the union members are
all the same size, this could just result in a compilation error.

> 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 a substantial stretch of user-code (which must be maintained as the
struct changes) is acceptable...

I think having a default struct-compare feature in the language would have
been useful.

--
Bartc

 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      12-08-2009
"bartc" <(E-Mail Removed)> writes:
> "Eric Sosman" <(E-Mail Removed)> wrote in message
> news:hfm3nb$25p$(E-Mail Removed)-september.org...

[...]
>> 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.


And even without padding bytes, or with an assurance that padding
bytes are set to zero, you might still have to worry about members
for which bitwise equality comparison doesn't work. Is +0 equal
to -0? What about pointers on a system where the same address can
have more than one representation? What about floating-point NaNs,
which aren't equal to themselves?

> But a substantial stretch of user-code (which must be maintained as the
> struct changes) is acceptable...
>
> I think having a default struct-compare feature in the language would have
> been useful.


How often is it reall useful?

I've worked on a compiler for a language (Ada) that does require
support for record (struct) equality comparison. In one version
of the compiler, we initialized the entire object to all-bits-zero
(which could impose significant overhead even when no comparison
is ever performed). In a later version, we generated code to
compare each member. And I don't remember ever actually *needing*
to compare two records/structs for equality. Logical equivalence
is very often more complicated than member-by-member equality.

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Eric Sosman
Guest
Posts: n/a
 
      12-08-2009
bartc wrote:
>
> "Eric Sosman" <(E-Mail Removed)> wrote in message
> news:hfm3nb$25p$(E-Mail Removed)-september.org...
>> Noob wrote:
>>> Hello,
>>>
>>> I don't understand why assignment of structs is supported,
>>> but comparison is not. It seems to me that the two operations
>>> would be of similar complexity, no?

>>
>> You're exactly right: "No." From the Rationale:
>>
>> 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.

>
> Interesting. I developed a pretty much parallel language to C in the
> 1980's.
>
> That /did/ have struct compares, and it seemed work!
>
> However, my structs didn't have 'holes', as I knew nothing about C's method
> of automatic padding (I did this manually as needed.)
>
> Even with holes, I can imagine various schemes to compare two structs that
> would not require an arbitrarily large amount of code (such as looping
> through a bitmap showing the bytes that need to match, or finding out
> exactly what the difficulty is in making sure padding bytes are zero) .


Padding bytes (and padding bits, for bit-fields) mightn't
be the only problem. For example:

struct { char c[100]; }
x = { "Hello" }, y = { "Hello" };
x.c[99] = 'x';
y.c[99] = 'y';
assert (strcmp(x.c, y.c) == 0);
assert (x == y); /* ??? */

The structs x,y are "equal" if their c arrays are thought of
as containing strings, "unequal" if they're thought of as
holding a hundred characters each. A related issue:

char xdata[] = "Hello", ydata[] = "Hello";
struct { char *p; }
x = { xdata }, y = { ydata };
assert (strcmp(x.p, y.p) == 0);
assert (x.p != y.p);
assert (x == y); /* ??? */

It would certainly be possible to define struct equality
as meaning "corresponding elements' values are equal," meaning
that the final assert() in each example would fail. But would
this be useful? Sometimes, perhaps, for "pure value" structs
like `struct point { int x, y; }'. But even for a tiny step
beyond simplicity it seems to me the programmer wants finer
control over which elements do and do not count towards "equal."
In `struct point { int x,y; struct point *next; }', for example,
it's likely that x,y would participate in the test but that the
linked list pointer would not.

>> The possibility of union-type elements in
>> a structure raises insuperable problems with this
>> approach.

>
> How would you compare two union values anyway? Unless the union members are
> all the same size, this could just result in a compilation error.


There's trouble even if they're the same size. Just suppose
float and int are the same size (as in a recent thread):

union { float f; int i; } x, y;
x.f = 42;
y.i = 42;
assert (x.f == y.i);
assert (x == y); /* ??? */

The compiler has no way to know which element it should check
for equality, since a union can contain different elements at
different times.

>> 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 a substantial stretch of user-code (which must be maintained as the
> struct changes) is acceptable...


Since it gives the programmer something of value -- namely,
a way to control which elements participate in the test, and what
notion of "equality" applies to them -- yes, I think so.

> I think having a default struct-compare feature in the language would have
> been useful.


For self-contained "value" structs, maybe. For others, I'm
not convinced. But try the experiment for yourself: Look through
a pile of code and find the places where structs are tested for
some kind of "equality." See if you think an automatically-
generated test would have worked instead of the hand-coded kind.
(The experiment isn't perfect, of course, but may be informative.)

--
Eric Sosman
(E-Mail Removed)lid
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Can *common* struct-members of 2 different struct-types, that are thesame for the first common members, be accessed via pointer cast to either struct-type? John Reye C Programming 28 05-08-2012 12:24 AM
Comparison of 2 files and generating the output based on comparison Deepu Perl Misc 1 02-07-2011 03:09 PM
sizeof(Struct::Member) rationale petschy C++ 8 09-03-2008 10:23 AM
Rationale behind constructor call chain... ( and comparison with C++) A.B. Java 13 11-03-2006 01:55 AM
struct my_struct *p = (struct my_struct *)malloc(sizeof(struct my_struct)); Chris Fogelklou C Programming 36 04-20-2004 08:27 AM



Advertisments