Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #30375

Re: Struct assignment

From Shao Miller <sha0.miller@gmail.com>
Newsgroups comp.lang.c
Subject Re: Struct assignment
Date 2013-01-20 01:06 -0500
Organization A noiseless patient Spider
Message-ID <kdg1ge$me$1@dont-email.me> (permalink)
References <u0fqs9-929.ln1@main.anatron.com.au> <kde706$3t0$1@dont-email.me> <simqs9-ue9.ln1@main.anatron.com.au> <kdeik4$b8s$1@dont-email.me> <0u0ss9-jv4.ln1@main.anatron.com.au>

Show all headers | View raw


On 1/19/2013 21:21, Russell Shaw wrote:
> On 20/01/13 03:45, Shao Miller wrote:
>> On 1/19/2013 09:18, Russell Shaw wrote:
>>> On 20/01/13 00:27, Eric Sosman wrote:
>>>> On 1/19/2013 7:09 AM, Russell Shaw wrote:
>>>>> Hi,
>>>>> In gcc-4.7 C99, i get an error (in a function scope):
>>>>>
>>>>> struct {
>>>>> int a;
>>>>> } sa;
>>>>>
>>>>> struct {
>>>>> int a;
>>>>> } sb;
>>>>>
>>>>> sb = sa;
>>>>>
>>>>> error: incompatible types when assigning to type 'struct <anonymous>'
>>>>> from type 'struct <anonymous>'
>>>>>
>>>>>
>>>>> ISO/IEC 9899:201x Committee Draft -- August 11, 2008 WG14/N1336
>>>>>
>>>>> 6.5.16.1 Simple assignment
>>>>> Para 1
>>>>> -- the left operand has a qualified or unqualified version of a
>>>>> structure or union type compatible with the type of the right;
>>>>>
>>>>>
>>>>> 6.2.7 Compatible type and composite type
>>>>> Para 1
>>>>> Two types have compatible type if their types are the same. Additional
>>>>> rules for determining whether two types are compatible are
>>>>> described in
>>>>> 6.7.2 for type specifiers, in 6.7.3 for type qualifiers, and in 6.7.5
>>>>> for declarators.48) Moreover, two structure, union, or enumerated
>>>>> types
>>>>> declared in separate translation units are compatible if their tags
>>>>> and
>>>>> members satisfy the following requirements: If one is declared with a
>>>>> tag, the other shall be declared with the same tag. If both are
>>>>> complete
>>>>> types, then the following additional requirements apply: there
>>>>> shall be
>>>>> a one-to-one correspondence between their members such that each
>>>>> pair of
>>>>> corresponding members are declared with compatible types, and such
>>>>> that
>>>>> if one member of a corresponding pair is declared with a name, the
>>>>> other
>>>>> member is declared with the same name. For two structures,
>>>>> corresponding
>>>>> members shall be declared in the same order. For two structures or
>>>>> unions, corresponding bit-fields shall have the same widths. For two
>>>>> enumerations, corresponding members shall have the same values.
>>>>>
>>>>>
>>>>> The above mentions "separate translation units", but i don't see
>>>>> why the
>>>>> error should happen.
>>>>
>>>> Um, er, because your `sa' and `sb' are not in separate
>>>> translation units? And hence aren't compatible?
>>>>
>>>> The fact that two types look the same (as yours do) doesn't
>>>> mean they actually are the same; it's just a coincidence of
>>>> their representation. On many systems `int' and `long' have
>>>> the same representation and even the same behavior, yet they
>>>> are distinct types nonetheless. (Incompatible types, too,
>>>> though implicit conversions often disguise the fact.)
>>>>
>>>> Have you ever run into the (in)famous "struct declaration
>>>> in parameter list" problem (FAQ Question 2.5)? That's very much
>>>> like what's happening here: Having written a type declaration
>>>> without a name (tag) or alias (typedef), you have no way to
>>>> designate that same type again.
>>>
>>> Why should it matter that the second struct is "declared" in a separate
>>> translation unit?
>>
>> The usual tradition for two translation units to use the same
>> programmer-defined
>> type is for them to both #include a header that defines that type. But
>> during
>> translation, it's not really the header that defines the type, it's the
>> translation unit. So we need to ask, "Is the type used in TU A the
>> same as in TU
>> B?" The discussion about compatible types answers this question.
>
> When both sa and sb are declared in the one common header, sb = sa still
> gives the same error.
>

Agreed.

> I just don't see why the point about being compatible between different
> translation units is made, when the same header declaration is going to
> be used in both anyway.
>

This doesn't quite make sense to me.  If you have one .h file that 
declares two objects, can you please explain:

   - In which .c file will 'sa' be defined?
   - In which .c file will 'sb' be defined?
   - In which .c file will the assignment occur?

I'm not sure which scenario you're imagining.

>>> To be able to do the assignment, you have to #include
>>> that second declaration in to the first file anyway.
>>>
>>
>> You don't have to #include anything. You can copy and paste the type's
>> definition manually, or the object's or function's
>> declaration/definition.
>>

Did you spot this part, above?

>>> It's easy to write a compiler to do that assignment deterministically,
>>> so why's it not allowed?
>>>
>>> p.6.2.7 describes the compatability for structs in separate translation
>>> units, but says nothing (ie, does not forbid) about assignments in the
>>> same translation unit.
>>
>> How can you argue that their types are the same in this circumstance?
>> Since the
>> type has no associated identifier, how can you be sure? Please
>> consider another
>> simple case (which presents the same issue):
>>
>> int main(void) {
>> if ((struct { int x; } *) 0 == (struct { int x; } *) 0)
>> return 0;
>> return 0;
>> }
>>
>> How do you know that these types are the same? How do you know how
>> many padding
>> bytes these two referenced (pointed-to) types have after their 'x'
>> members? How
>> do you know the alignment requirements of the referenced types?
>
> Both types are structurally the same because they're both pointers to
> structs that are built the same way.
>

There are plenty of types whose representation and alignment 
requirements match.  Does that mean that they should be interchangeable? 
  That was the point of my "apples" and "oranges" example, just below. 
Type is something more than representation and alignment.  It means you 
can say "these things are different than these other things, and should 
not be mixed up."  How would you ensure that things don't get mixed up 
inappropriately if representation and alignment was good enough for 
compatibility?

> I'm assuming those two structs are built the same way with the same
> padding, because if they weren't, the compiler ABI is then randomly
> inconsistant.
>

Yes, I'd agree that you're probably right close to 100% of the time, 
especially due to the "common initial sequence" discussion for unions 
and due to the compatibility requirement across translation units.  I 
think a problem is your use of "ABI", which doesn't have a meaning in 
the Standard.

>> Suppose you have:
>>
>> typedef int tni;
>> struct { int size; } apple;
>> struct { tni size; } orange;
>>
>> Should these two objects be considered to have the same type, if we
>> saw these in
>> the same translation unit? It could be that the _intention_ is for
>> each to
>> belong to a different domain, and the discussion of compatible types
>> helps to
>> prevent against accidental crossing of domains.
>
> That's what i'd like to see,

That's not what _I'd_ like to see!  I want type safety that allows me to 
specify different domains of values, without any care for internal 
representational co-incidences.  I don't want to accidentally compare 
apples and oranges.

> but i was trying to figure out how
> assignments between them can be done if they come from different
> translation units.
>

Translation unit #1:

   struct { int i; double d; } foo;

Translation unit #2:

   extern struct { int i; double d; } foo;

Now the type of 'foo' in TU #1 can be said to be compatible with the 
type in TU #2.

> I cannot devise how sb = sa can be found in any source, where sb and sa
> have separate struct declarations.
>

Why you are searching for such a case?  Type compatibility is used in a 
lot of places other than assignment.  As just one example, suppose you have:

Translation unit #1:

   static struct { int i; double d; } foo;
   void * foo_ptr = &foo;

   void callme(void) {
       if (foo.i == 42 && foo.d == 3.14159)
         /* Success */
         return;
     }

Translation unit #2:

   extern void callme(void);
   extern void * foo_ptr;

   static struct { int i; double d; } bar;

   static void somefunc(void) {
       bar.i = 42;
       bar.d = 3.14159;
       memcpy(foo_ptr, &bar, sizeof bar);
       callme();
     }

If 'foo' and 'bar' didn't have compatible types, then when 'somefunc' 
calls 'callme' and 'callme' tries to read the value of 'foo.i' and 
'foo.d', it'd be undefined behaviour.  Because they have compatible 
types, things are ok.

>
> The only use case i can think of is:
>
>
> Translation unit1:
>
> // tu1.h header:
> struct {
>    int a;
> } sb;
>
> struct sb *str_new(void);
>
>
> // tu1.c
> struct {
>    int a;
> } sa;
>
> struct sa *str_new(void)
> {
>    struct sa *str = malloc(sizeof(struct sa));
>    return str;
> }

I don't quite follow the point of this code.

(Minor note: The pattern:

   obj_type * ptr = malloc(sizeof *ptr);

says "Allocate enough storage for the pointee" whereas your version says 
"Allocate enough storage for obj_type", which happens to match the right 
size for the pointee.)

Here is a thought experiment:

Imagine that 9 out of 10 people want:

   struct { int i; } root;

to represent a one-of-a-kind object, that should never be compared with 
any other object, even if there is an object like:

   struct { int i; } starting_point;

Now imagine that you need to be able to access 'root' from any other 
translation unit.  You can make a header for those _other_ translation 
units:

   extern struct { int i; } root;

Because the header is actually part of each of the other translation 
units, type compatibility says that the all of the translation units 
think that 'root' is the same type.

Here is a different thought experiment:

Imagine that 1 out of 10 people want:

   struct { int i; } count;

and:

   struct { int i; } number;

to have the same type because they have the same composition, and want 
to be able to assign the values of these objects to one another because 
both are objects that might make sense in the same domain.

Now imagine that 1 out of 10 people see a strange rule that seems to 
interfere with this goal, but seems to allow it when the objects are in 
different translation units.  In fact, if the two objects are declared 
in two translation units (as a header #inclusion would do), the 
allowance doesn't even have any benefit for the goal!

But the two sets of people in these thought experiments have different 
goals.  These thought experiments aren't offered as an actual 
representation of the world, but as a possible way to understand how 
people with different goals can view the rules very differently.

(The 9 people might say to the 1 person, "so identify the type so it can 
be re-used, then we both win, to an extent.")

-- 
- Shao Miller
--
"Thank you for the kind words; those are the kind of words I like to hear.

Cheerily,"  -- Richard Harter

Back to comp.lang.c | Previous | Next — Previous in thread | Next in thread | Find similar | Unroll thread


Thread

Struct assignment Russell Shaw <rjshawN_o@s_pam.netspace.net.au> - 2013-01-19 23:09 +1100
  Re: Struct assignment Eric Sosman <esosman@comcast-dot-net.invalid> - 2013-01-19 08:27 -0500
    Re: Struct assignment Russell Shaw <rjshawN_o@s_pam.netspace.net.au> - 2013-01-20 01:18 +1100
      Re: Struct assignment "BartC" <bc@freeuk.com> - 2013-01-19 14:59 +0000
      Re: Struct assignment Eric Sosman <esosman@comcast-dot-net.invalid> - 2013-01-19 11:25 -0500
        Re: Struct assignment Russell Shaw <rjshawN_o@s_pam.netspace.net.au> - 2013-01-20 12:46 +1100
          Re: Struct assignment Bart van Ingen Schenau <bart@ingen.ddns.info.invalid> - 2013-01-20 09:20 +0000
          Re: Struct assignment Eric Sosman <esosman@comcast-dot-net.invalid> - 2013-01-20 09:08 -0500
            Re: Struct assignment Russell Shaw <rjshawN_o@s_pam.netspace.net.au> - 2013-01-21 12:02 +1100
              Re: Struct assignment Eric Sosman <esosman@comcast-dot-net.invalid> - 2013-01-20 22:08 -0500
                Re: Struct assignment James Kuyper <jameskuyper@verizon.net> - 2013-01-20 23:21 -0500
              Re: Struct assignment James Kuyper <jameskuyper@verizon.net> - 2013-01-21 08:23 -0500
                Re: Struct assignment Russell Shaw <rjshawN_o@s_pam.netspace.net.au> - 2013-01-22 13:33 +1100
                Re: Struct assignment Russell Shaw <rjshawN_o@s_pam.netspace.net.au> - 2013-01-23 19:53 +1100
      Re: Struct assignment Shao Miller <sha0.miller@gmail.com> - 2013-01-19 11:45 -0500
        Re: Struct assignment Russell Shaw <rjshawN_o@s_pam.netspace.net.au> - 2013-01-20 13:21 +1100
          Re: Struct assignment Shao Miller <sha0.miller@gmail.com> - 2013-01-20 01:06 -0500
            Re: Struct assignment Russell Shaw <rjshawN_o@s_pam.netspace.net.au> - 2013-01-20 18:03 +1100
  Re: Struct assignment glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2013-01-19 19:18 +0000
    Re: Struct assignment James Kuyper <jameskuyper@verizon.net> - 2013-01-19 15:22 -0500
      Re: Struct assignment Shao Miller <sha0.miller@gmail.com> - 2013-01-19 15:47 -0500
      Re: Struct assignment Eric Sosman <esosman@comcast-dot-net.invalid> - 2013-01-19 17:56 -0500
        Re: Struct assignment Tim Rentsch <txr@alumni.caltech.edu> - 2013-01-20 12:12 -0800
  Re: Struct assignment falk@rahul.net (Edward A. Falk) - 2013-01-19 23:41 +0000
    Re: Struct assignment glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2013-01-20 01:01 +0000
    Re: Struct assignment James Kuyper <jameskuyper@verizon.net> - 2013-01-19 20:53 -0500
      Re: Struct assignment Tim Rentsch <txr@alumni.caltech.edu> - 2013-01-20 12:03 -0800

csiph-web