[comp.std.c] Two standards problems

clive@ixi.UUCP (Clive Feather) (06/06/89)

I have two problems concerning ANSI-C, in relation to the X Window System
(you don't need to know about / be interested in X to understand these).

Firstly, the Xt Intrinsics define a macro called XtOffset. This is similar
to offsetof, but:

    (1) the type argument is a pointer to a structure
    (2) the field designator can specify a field of a field

In other words, suppose I have:

    typedef struct
    {
        int a;
        double b;
        struct
        {
            long x;
            char y;
            float z;
        } c;
        char *d;
    } funny;
    typedef funny *funny_p;

    unsigned int i;
    funny fred;
    char *cp;

then I can write:

    i = XtOffset (funny_p, x.y);

followed by:

    cp = ((char *) & fred) + i;
    *cp = 'x';

The present definition of XtOffset is:

    #define XtOffset(type,field) \
    ((unsigned int) (((char *) (& (((type) NULL)->field))) - ((char *) NULL)))

(Q1) Is the present definition legal and portable ANSI-C ?
(Q2) Is it possible to define XtOffset portably using offsetof ?
(Q3) If the answer to both the above is no, then is it possible to define XtOffset
     portably ?


The second, unrelated, problem is to do with structure padding. Suppose I have the
following two structures:

    typedef struct
    {
        struct
        {
            char c1;
            char c2;
            char c3;
            char c4;
            char c5;
            char c6;
        } all;
    }
    t1;

    typedef struct
    {
        struct
        {
            char c1;
            char c2;
            char c3;
        } upper;
        struct
        {
            char c4;
            char c5;
            char c6;
        } lower;
    }
    t2;

    union
    {
        t1 m1;
        t2 m2;
    } u;

(Q4) It is my understanding that c1, c2, and c3 must have the same position in
     the two versions, so that assigning to u.m1.all.c1 and then reading from
     u.m2.upper.c1 will yield the same value. Is this correct ?
(Q5) Can the compiler insert padding between t2.upper and t2.lower so that
     u.m1.all.c4 and u.m2.lower.c4 occupy different locations ?

Suppose I have the variables:

    t1 var1;
    t2 var2;

    t1 *pt1;
    t2 *pt2;

    pt1 = (t1 *) & var2;
    pt2 = (t2 *) & var1;

    /* pt1 points to var2 as a t1, and vice versa */

(Q6) Will writing to pt1->all.c1   write into var2.upper.c1, and
          writing to pt2->upper.c1 write into var1.all.c1        ?
(Q7) Will writing to pt1->all.c4   write into var2.lower.c4, and
          writing to pt2->lower.c4 write into var1.all.c4        ?
[These are equivalent to Q4 and Q5, but with casts instead of unions].

In all six questions, I am looking for answers in terms of what is portable to
*all* conforming systems.

For those who say "why on earth are you doing this ?", the answer is basically
"backwards compatibility"; incompatible changes must be avoided if at all possible.
----
Clive D.W. Feather
IXI Limited
clive@ixi.uucp
...!uunet!ukc!ixi!clive (riskier)

clive@ixi.UUCP (Clive Feather) (06/12/89)

The story so far:

I originally posted this as article <178@ixi.UUCP in comp.std.c. Following
the deafening silence, I am reposting it. Please let me emphasise that I am
interested only in *standards* answers - it is of no use to tell me that this
works on XYZ system (which proves nothing), doesn't work in XYZ system (which
isn't an ANSI compiler), or doesn't work on XYZ system (which has a compiler
which claims to be ANSI but gets something wrong). The answers will be used
to generate code which must be strictly conforming.

Now read on ...

I have two problems concerning ANSI-C, in relation to the X Window System
(you don't need to know about / be interested in X to understand these).

Firstly, the Xt Intrinsics define a macro called XtOffset. This is similar
to offsetof, but:

    (1) the type argument is a pointer to a structure
    (2) the field designator can specify a field of a field

In other words, suppose I have:

    typedef struct
    {
        int a;
        double b;
        struct
        {
            long x;
            char y;
            float z;
        } c;
        char *d;
    } funny;
    typedef funny *funny_p;

    unsigned int i;
    funny fred;
    char *cp;

then I can write:

    i = XtOffset (funny_p, x.y);

followed by:

    cp = ((char *) & fred) + i;
    *cp = 'x';

The present definition of XtOffset is:

    #define XtOffset(type,field) \
    ((unsigned int) (((char *) (& (((type) NULL)->field))) - ((char *) NULL)))

(Q1) Is the present definition legal and portable ANSI-C ?
(Q2) Is it possible to define XtOffset portably using offsetof ?
(Q3) If the answer to both the above is no, then is it possible to define XtOffset
     portably ?


The second, unrelated, problem is to do with structure padding. Suppose I have the
following two structures:

    typedef struct
    {
        struct
        {
            char c1;
            char c2;
            char c3;
            char c4;
            char c5;
            char c6;
        } all;
    }
    t1;

    typedef struct
    {
        struct
        {
            char c1;
            char c2;
            char c3;
        } upper;
        struct
        {
            char c4;
            char c5;
            char c6;
        } lower;
    }
    t2;

    union
    {
        t1 m1;
        t2 m2;
    } u;

(Q4) It is my understanding that c1, c2, and c3 must have the same position in
     the two versions, so that assigning to u.m1.all.c1 and then reading from
     u.m2.upper.c1 will yield the same value. Is this correct ?
(Q5) Can the compiler insert padding between t2.upper and t2.lower so that
     u.m1.all.c4 and u.m2.lower.c4 occupy different locations ?

Suppose I have the variables:

    t1 var1;
    t2 var2;

    t1 *pt1;
    t2 *pt2;

    pt1 = (t1 *) & var2;
    pt2 = (t2 *) & var1;

    /* pt1 points to var2 as a t1, and vice versa */

(Q6) Will writing to pt1->all.c1   write into var2.upper.c1, and
          writing to pt2->upper.c1 write into var1.all.c1        ?
(Q7) Will writing to pt1->all.c4   write into var2.lower.c4, and
          writing to pt2->lower.c4 write into var1.all.c4        ?
[These are equivalent to Q4 and Q5, but with casts instead of unions].

In all six questions, I am looking for answers in terms of what is portable to
*all* conforming systems.

For those who say "why on earth are you doing this ?", the answer is basically
"backwards compatibility"; incompatible changes must be avoided if at all possible.
-- 
Clive D.W. Feather
IXI Limited
clive@ixi.uucp
...!uunet!ukc!ixi!clive (riskier)

dfp@cbnewsl.ATT.COM (david.f.prosser) (06/14/89)

In article <183@ixi.UUCP> clive@ixi.uucp (Clive Feather) writes:
>Firstly, the Xt Intrinsics define a macro called XtOffset. This is similar
>to offsetof, but:
>
>    (1) the type argument is a pointer to a structure
>    (2) the field designator can specify a field of a field
>
>In other words, suppose I have:
>
	[example deleted for inews sake...]

>The present definition of XtOffset is:
>
>    #define XtOffset(type,field) \
>    ((unsigned int) (((char *) (& (((type) NULL)->field))) - ((char *) NULL)))
>
>(Q1) Is the present definition legal and portable ANSI-C ?

The construction is not portable, even though it will work with many compilers.

>(Q2) Is it possible to define XtOffset portably using offsetof ?

Yes.  Try:
	#define XtOffset(p, m) offsetof(*(p), m)

>The second, unrelated, problem is to do with structure padding. Suppose I have the
>following two structures:
>
	[examples deleted for inews sake...]

>(Q4) It is my understanding that c1, c2, and c3 must have the same position in
>     the two versions, so that assigning to u.m1.all.c1 and then reading from
>     u.m2.upper.c1 will yield the same value. Is this correct ?

Yes.

>(Q5) Can the compiler insert padding between t2.upper and t2.lower so that
>     u.m1.all.c4 and u.m2.lower.c4 occupy different locations ?

Also yes.
>
>Suppose I have the variables:
>
	[examples deleted for inews sake...]

>(Q6) Will writing to pt1->all.c1   write into var2.upper.c1, and
>          writing to pt2->upper.c1 write into var1.all.c1        ?

Yes.

>(Q7) Will writing to pt1->all.c4   write into var2.lower.c4, and
>          writing to pt2->lower.c4 write into var1.all.c4        ?

Not necessarily since (as you noted above) there may be padding
between upper and lower.

>[These are equivalent to Q4 and Q5, but with casts instead of unions].
>
>In all six questions, I am looking for answers in terms of what is portable to
>*all* conforming systems.
>
>For those who say "why on earth are you doing this ?", the answer is basically
>"backwards compatibility"; incompatible changes must be avoided if at all possible.
>-- 
>Clive D.W. Feather
>IXI Limited
>clive@ixi.uucp
>...!uunet!ukc!ixi!clive (riskier)

[padding for inews sake...]
x
x
x
x
x
x
x
x
x
x
x
x

Dave Prosser	...not an official X3J11 answer...

gwyn@smoke.BRL.MIL (Doug Gwyn) (06/14/89)

In article <183@ixi.UUCP> clive@ixi.uucp (Clive Feather) writes:
>    i = XtOffset (funny_p, x.y);

Presumably that was c.y, not x.y.

>(Q1) Is the present definition legal and portable ANSI-C ?

No -- you cannot dereference through a null pointer nor perform arithmetic
with it.

>(Q2) Is it possible to define XtOffset portably using offsetof ?

Not as it's currently defined, because there's no way (that I can think of)
to convert a struct pointer type name into the type of the struct.

>(Q3) If the answer to both the above is no, then is it possible to define XtOffset
>     portably ?

Not that I can see.

>(Q4) It is my understanding that c1, c2, and c3 must have the same position in
>     the two versions, so that assigning to u.m1.all.c1 and then reading from
>     u.m2.upper.c1 will yield the same value. Is this correct ?

No, although it will usually be the case.  The Standard imposes some
weird constraints on addresses of first members of structs that pretty
much guarantee this working on any sane implementation.

>(Q5) Can the compiler insert padding between t2.upper and t2.lower so that
>     u.m1.all.c4 and u.m2.lower.c4 occupy different locations ?

The compiler can generate padding anywhere in a struct (except before
the first member), and it doesn't have to follow reasonable rules in
doing so, just so long as it keeps it all straight internally.

>(Q6) Will writing to pt1->all.c1   write into var2.upper.c1, and
>          writing to pt2->upper.c1 write into var1.all.c1        ?

Assuming the compiler let you get away with the pointer casts in the
first place, which I think could be deduced from various constraints
of the Standard (with a lot of effort!), this is likely to work, as
indicated previously.

>(Q7) Will writing to pt1->all.c4   write into var2.lower.c4, and
>          writing to pt2->lower.c4 write into var1.all.c4        ?
>[These are equivalent to Q4 and Q5, but with casts instead of unions].

These are marginally less likely to work than in Q6.

There are of course alternative ways to do these things portably,
although as you seem to realize, the interfaces would have to be
changed.  One wonders why this is being thought about now instead
of when the interfaces were first "designed".

dfp@cbnewsl.ATT.COM (david.f.prosser) (06/14/89)

In article <10397@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes:
}In article <183@ixi.UUCP> clive@ixi.uucp (Clive Feather) writes:
}>(Q2) Is it possible to define XtOffset portably using offsetof ?
}
}Not as it's currently defined, because there's no way (that I can think of)
}to convert a struct pointer type name into the type of the struct.
}
}>(Q3) If the answer to both the above is no, then is it possible to define XtOffset
}>     portably ?
}
}Not that I can see.

Doug is quite right.  I was mistaken in my previous reply.  The only other
idea that I have would rely on having a common prefix or suffix to a single
typedef structure pointer type name that would generate the structure type:

	typedef struct { /*...*/ } funny;
	typedef funny *funny_p;

	typedef funny funny_p_deref_type;

	#define XtOffset(p, m) offsetof(p##_deref_type, m)

This relies on having only single identifier first arguments to all XtOffset()
invocations, and that each such identifier has a _deref_type-suffixed version
available.  This is going a long way to get around this problem.  Is it really
impossible simply to change the XtOffset() invocations to their matching
offsetof() invocations, since the only change is to the first argument?

}
}>(Q4) It is my understanding that c1, c2, and c3 must have the same position in
}>     the two versions, so that assigning to u.m1.all.c1 and then reading from
}>     u.m2.upper.c1 will yield the same value. Is this correct ?
}
}No, although it will usually be the case.  The Standard imposes some
}weird constraints on addresses of first members of structs that pretty
}much guarantee this working on any sane implementation.
}
}>(Q5) Can the compiler insert padding between t2.upper and t2.lower so that
}>     u.m1.all.c4 and u.m2.lower.c4 occupy different locations ?
}
}The compiler can generate padding anywhere in a struct (except before
}the first member), and it doesn't have to follow reasonable rules in
}doing so, just so long as it keeps it all straight internally.
}
}>(Q6) Will writing to pt1->all.c1   write into var2.upper.c1, and
}>          writing to pt2->upper.c1 write into var1.all.c1        ?
}
}Assuming the compiler let you get away with the pointer casts in the
}first place, which I think could be deduced from various constraints
}of the Standard (with a lot of effort!), this is likely to work, as
}indicated previously.
}
}>(Q7) Will writing to pt1->all.c4   write into var2.lower.c4, and
}>          writing to pt2->lower.c4 write into var1.all.c4        ?
}>[These are equivalent to Q4 and Q5, but with casts instead of unions].
}
}These are marginally less likely to work than in Q6.
}
}There are of course alternative ways to do these things portably,
}although as you seem to realize, the interfaces would have to be
}changed.  One wonders why this is being thought about now instead
}of when the interfaces were first "designed".

I disagree here, Doug.  The pANS does allow for virtually any padding
within structures, but when the initial portions of such type declarations
are identical, they are guaranteed to match.  See section 3.3.2.3.

Dave Prosser	...not an official X3J11 answer...

gwyn@smoke.BRL.MIL (Doug Gwyn) (06/17/89)

In article <800@cbnewsl.ATT.COM> dfp@cbnewsl.ATT.COM (david.f.prosser) writes:
>	#define XtOffset(p, m) offsetof(*(p), m)

In preparing my previous response to the question, I considered something
similar, but it wasn't clear to me from the draft Standard exactly what
was acceptable for the "type" argument to offsetof().  In particular the
use of
	static type t;
in the Standard bothered me; if one substitutes literally for "type" in
that template, will constructs such as "*(p)" where "p" is a type name
work?  Some types need the identifier "t" buried inside them.  Anyway,
the proper declaration in this case would seem to be
	static p *t;
so shouldn't the "type" argument to offsetof() be "p*"?  I don't think
this was specified clearly enough in the draft (although I would be happy
to be proved wrong on this point).

gwyn@smoke.BRL.MIL (Doug Gwyn) (06/17/89)

In article <806@cbnewsl.ATT.COM> dfp@cbnewsl.ATT.COM (david.f.prosser) writes:
>I disagree here, Doug.  The pANS does allow for virtually any padding
>within structures, but when the initial portions of such type declarations
>are identical, they are guaranteed to match.  See section 3.3.2.3.

I thought that was what I said, although I may have gotten confused using
the names "c1", "c4", etc.  It is the "second half" of the composite
structure that may well cause problems, due to padding being inserted
between the first and second halves.  For example, if the first half was
supposed to map onto 3 chars and the second half ditto, an implementation
that always aligns structs on 4-byte boundaries would insert a pad byte
at the end of the first nominally 3-byte structure so that the second
member of the composite structure would be properly aligned.  Thus, if one
tried to map the composite structure onto a simple array of 6 chars (or
onto a simple structure with 6 consecutive char members), it wouldn't fit
properly past the third byte.

Structure padding is such a pain that I don't recommend using such an
approach in portable code.  Much better to roll the data bytes into a
simple array (or equivalent unpadded object), then construct the objects
represented by the raw data bytes through explicit assembly, e.g.
	n_params = data[2] | data[3]<<8 | data[4]<<16 | data[5]<<24;
There are non-portable ways to "cheat", in order to get slightly more
efficient code for this operation, but the odds are that the cost of doing
the input dwarfs the cost of assembling the desired objects, so there is
no appreciable gain from such "cheats".

dfp@cbnewsl.ATT.COM (david.f.prosser) (06/20/89)

In article <10412@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes:
>In article <800@cbnewsl.ATT.COM> dfp@cbnewsl.ATT.COM (david.f.prosser) writes:
>>	#define XtOffset(p, m) offsetof(*(p), m)
>
>In preparing my previous response to the question, I considered something
>similar, but it wasn't clear to me from the draft Standard exactly what
>was acceptable for the "type" argument to offsetof().  In particular the
>use of
>	static type t;
>in the Standard bothered me; if one substitutes literally for "type" in
>that template, will constructs such as "*(p)" where "p" is a type name
>work?  Some types need the identifier "t" buried inside them.  Anyway,
>the proper declaration in this case would seem to be
>	static p *t;
>so shouldn't the "type" argument to offsetof() be "p*"?  I don't think
>this was specified clearly enough in the draft (although I would be happy
>to be proved wrong on this point).

Doug makes an interesting case on this point.  The complete pANS description
for offsetof is:

	The macros [in <stddef.h>] are ... and

		offsetof(_type_, _member-designator_)

	which expands to an integral constant expression that has type
	size_t, the value of which is the offset in bytes, to the structure
	member (designated by _member-designator_), from the beginning of
	its structure (designated by _type_).  The _member-designator_
	shall be such that given

		static _type_ t;

	then the expression &(t._member-designator_) evaluates to an
	address constant.  (If the specified member is a bit-field, the
	behavior is undefined.)

The most common implementation of offsetof (and mentioned as such in the
Rationale) is probably close to

	#define offsetof(t, m) ((size_t)&(((t *)0)->m))

but this just doesn't "cut it" with the interpretation that _type_ is only
constrained by the "static _type_ t;" construct.  With an implementation of

	#define XtOffset(p, m) offsetof(p *, m)

an invocation of

	XtOffset(x, a.b)

produces

	((size-t)&(((x * *)0)->a.b))

which casts 0 to be a pointer to a pointer to an x (which in the original
was a pointer to the structure in question).  By this, it is clear that the
Committee's intent with respect to offsetof was not to allow an arbitrary
substitution for _type_ in the pseudo-declaration.

Unfortunately, the only support (just from the pANS) for this was the
note that a structure is designated by _type_.  Given that one can designate
a structure either by a prefix * applied to an expression with structure
pointer type, or a postfix * in a declaration in which the type specifier is
a structure pointer, you are right that the words are not completely clear.
(The Committee did not think about the second case, I'm sure.)

As I recall, this description was used so that a chain of members (e.g.
a.b.c) would be valid, which the previous description did not permit.

This is exactly the sort of ruling that the interpretations phase would
produce.  In this case, the Rationale clarifies the pANS, so the above
form for XtOffset is not valid.

I still believe that the only means to build a structure type from a
structure pointer type name is through name creation with the ## operator,
as I outlined in my previous posting.

Dave Prosser	...not an official X3J11 answer...

dfp@cbnewsl.ATT.COM (david.f.prosser) (06/20/89)

In article <186@ixi.UUCP> clive@ixi.uucp (Clive Feather) writes:
}In article <183@ixi.UUCP> I asked two questions on ANSI C.
}My thanks to Doug Gwyn, David Prosser, and Pardo for answering.
}
}Now, the sequel. Just to be confusing, the topics are in reverse order.
}Once again, I only want ANSI standard answers.
}
}First topic (structure alignment)
}=================================
}
}I have three structure types: t_all, t_first, and t_last. The initial fields
}of t_all and t_first are the same. Suppose I define the following structured
}types:
}
}    typedef                      typedef
}    {                            {
}        t_all all;                   t_first first;
}    }                                t_last  last;
}    t_whole;                     }
}                                 t_joined;
}
}and the union:
}
}    union
}    {
}        t_whole  whole;
}        t_joined joined;
}    }
}    u;
}
}Then ANSI requires that a value written into one of the common fields of
}u.whole.all be readable out of the same field in u.joined.first.

Well...not exactly.  By adding another level of types, the code no longer
matches precisely the ANSI C description:

	With one exception, if a member of a union object is accessed after
	a value has been stored in a different member of the object, the
	behavior is implementation-defined.  One special guarantee is made
	in order to simplify the use of unions: If a union contains several
	structures that share a common initial sequence, and if the union
	object currently contains one of these structures, it is permitted
	to inspect the common initial part of any of them.  Two structures
	share a *common initial sequence* if corresponding members have
	compatible types (and, for bit-fields, the same widths) for a
	sequence of one or more initial members.

Since t_whole and t_joined do not share a common initial sequence, the
guarantee does not so exist (even though the first member of these two
structures do share a common initial sequence).  However, it is extremely
likely that this will work on any conforming implementation, and is likely
to be part of the Committee's intent.  The problem is that there is no
straightforward wording of this guarantee that really describes the
Committee's intent, and they chose to "live with" the imperfect current
wording.

}
}My questions:
}
}(Q8)  Do the names of the common initial fields of t_all and t_first have to
}      be the same for this to work, or is it sufficient for the types to be
}      identical ?

Names do not matter.  See the above quote.

}(Q9)  It seems to me that, since the union might only appear in one source
}      file, whilst the structures might be used in several, that the padding
}      of a structure depend *only* on the types of the fields of the
}      structure. Is this so ? If so, how do I get X3J11 to mandate it.

As I read the pANS, you are right that the padding can only be type-dependent.
This follows (in my reading) from the above quote and the rules for cross-
translation unit type compatibility, but is not directly stated as such.  To
get "X3J11 to mandate it" can only be done, at this point, by sending in a
query to the Committee.  Some time later an Information Bulletin from ANSI
will be issued with the answer.  However, this does not carry the same weight
as the Standard.

}
}I have many other structure types. All are of the form:
}
}    typedef
}    {
}        t_part_1 part_1;
}        t_part_2 part_2;
}        t_part_2 part_3;
}    }
}    *t_3_parts;
}
}I.e. I have t_1_parts, t_2_parts, t_3_parts, and so on; they are all pointers to
}structures, and all begin with a t_part_1 field. Further, all these field types
}are actually structures.
}
}(Q10) Do all the t_n_parts types have the same alignment requirements ? For
}      historical reasons, there are many functions which take an argument of
}      type t_1_parts, which is actually a value of one of the other types cast
}      correctly. These functions only access the part_1 fields.

Functionally, I believe that the pANS requires that all structure and union
pointers have the same alignment and size, but it may be possible to design
a conforming implementation that does not do so.  The Standard does not make
any direct requirement about such.

}
}
}Second topic (offsets)
}======================
}
}The Xt Intrinsics have a macro XtOffset. This is similar to the offsetof
}macro defined by ANSI. The call "XtOffset (T *, field)" is equivalent to
}"offsetof (T, field)", except that in the former the field may contain
}dot operators, and the type specified will normally be a typedefed pointer,
}rather than a construction with a *.

No.  offsetof requires a first argument that is a structure type.  "T *"
is not such in a cast context.  See my previous posting.

}
}(Q11) Can offsetof take "field1.field2" as its second argument ?

Yes.  I thought Doug's and my letter were clear on that point.

}(Q12) If not, can I add the offset of the sub-structure in the main one
}      and the field in the substructure to get the right effect ?
}      (I.e. can I use offsetof (T, field1) + offsetof (SUBT, field2)
}      to get the effect of offsetof (T, field1.field2).

Yes.

}
}The Intrinsics, in effect, have several functions which look similar to
}the following:
}
}    void GetValue (t_1_parts object, size_t size, offset_t offset, int magic)
}    /* I assume that offsetof returns an offset_t */
No, it is an expression with type size_t.  I don't know what an offset_t is.
}    /* See above for t_1_parts, and note Q10 */
}    {
}        void *value_ptr;
}
}        /*
}            The caller has some structure of the type pointed to by one of
}            the t_n_parts types; call this structure S and its type ST. In
}            addition, S has some field F of type FT (F may be a field of a
}            field of S). The caller will guarantee that:
}
}                object == (t_1_parts *) &S
}                size   == sizeof (FT)
}                offset == XtOffset (ST *, F)
}        */
}
}        /*
}            This comment is replaced by code which takes the value magic and
}            sets value_ptr to the address of a value of type FT, cast to
}            void *.
}        */
}
}        /*
}            The next statement *should*, in my opinion, carry out the following
}            assignment:
}
}                S.F = * (FT *) value_ptr;
}
}            or if you prefer:
}
}                ((ST *) object)->F = * (FT *) value_ptr;
}        */
}
}        memcpy ((void *) object + offset, value_ptr, size);

You cannot do pointer arithmetic on a void *.  You need to cast to some
version of char *.

}    }
}
}(Q13) Does ANSI guarantee that, given the assertions in the various comments,
}      the call to memcpy will do the assignment ?

If I've understood what is trying to be done here, yes, the fixed call
to memcpy will provide the effect ofa simple assignment in which all the
actual types are known.

}(Q14) If not, how do I write the last part of GetValue ?

Use char *, as noted above.

}
}
}Once again, my thanks (in advance) to those that answer.

Of course, you still have a problem with the calls to GetValue since there
is no simple portable version of XtOffset.

}-- 
}Clive D.W. Feather
}IXI Limited
}clive@ixi.uucp
}...!uunet!ukc!ixi!clive (riskier)

Dave Prosser	...not an official X3J11 answer...

clive@ixi.UUCP (Clive Feather) (07/22/89)

In article <183@ixi.UUCP> I asked two questions on ANSI C.
My thanks to Doug Gwyn, David Prosser, and Pardo for answering.

Now, the sequel. Just to be confusing, the topics are in reverse order.
Once again, I only want ANSI standard answers.

First topic (structure alignment)
=================================

I have three structure types: t_all, t_first, and t_last. The initial fields
of t_all and t_first are the same. Suppose I define the following structured
types:

    typedef                      typedef
    {                            {
        t_all all;                   t_first first;
    }                                t_last  last;
    t_whole;                     }
                                 t_joined;

and the union:

    union
    {
        t_whole  whole;
        t_joined joined;
    }
    u;

Then ANSI requires that a value written into one of the common fields of
u.whole.all be readable out of the same field in u.joined.first.

My questions:

(Q8)  Do the names of the common initial fields of t_all and t_first have to
      be the same for this to work, or is it sufficient for the types to be
      identical ?
(Q9)  It seems to me that, since the union might only appear in one source
      file, whilst the structures might be used in several, that the padding
      of a structure depend *only* on the types of the fields of the
      structure. Is this so ? If so, how do I get X3J11 to mandate it.

I have many other structure types. All are of the form:

    typedef
    {
        t_part_1 part_1;
        t_part_2 part_2;
        t_part_2 part_3;
    }
    *t_3_parts;

I.e. I have t_1_parts, t_2_parts, t_3_parts, and so on; they are all pointers to
structures, and all begin with a t_part_1 field. Further, all these field types
are actually structures.

(Q10) Do all the t_n_parts types have the same alignment requirements ? For
      historical reasons, there are many functions which take an argument of
      type t_1_parts, which is actually a value of one of the other types cast
      correctly. These functions only access the part_1 fields.


Second topic (offsets)
======================

The Xt Intrinsics have a macro XtOffset. This is similar to the offsetof
macro defined by ANSI. The call "XtOffset (T *, field)" is equivalent to
"offsetof (T, field)", except that in the former the field may contain
dot operators, and the type specified will normally be a typedefed pointer,
rather than a construction with a *.

(Q11) Can offsetof take "field1.field2" as its second argument ?
(Q12) If not, can I add the offset of the sub-structure in the main one
      and the field in the substructure to get the right effect ?
      (I.e. can I use offsetof (T, field1) + offsetof (SUBT, field2)
      to get the effect of offsetof (T, field1.field2).

The Intrinsics, in effect, have several functions which look similar to
the following:

    void GetValue (t_1_parts object, size_t size, offset_t offset, int magic)
    /* I assume that offsetof returns an offset_t */
    /* See above for t_1_parts, and note Q10 */
    {
        void *value_ptr;

        /*
            The caller has some structure of the type pointed to by one of
            the t_n_parts types; call this structure S and its type ST. In
            addition, S has some field F of type FT (F may be a field of a
            field of S). The caller will guarantee that:

                object == (t_1_parts *) &S
                size   == sizeof (FT)
                offset == XtOffset (ST *, F)
        */

        /*
            This comment is replaced by code which takes the value magic and
            sets value_ptr to the address of a value of type FT, cast to
            void *.
        */

        /*
            The next statement *should*, in my opinion, carry out the following
            assignment:

                S.F = * (FT *) value_ptr;

            or if you prefer:

                ((ST *) object)->F = * (FT *) value_ptr;
        */

        memcpy ((void *) object + offset, value_ptr, size);
    }

(Q13) Does ANSI guarantee that, given the assertions in the various comments,
      the call to memcpy will do the assignment ?
(Q14) If not, how do I write the last part of GetValue ?


Once again, my thanks (in advance) to those that answer.
-- 
Clive D.W. Feather
IXI Limited
clive@ixi.uucp
...!uunet!ukc!ixi!clive (riskier)

gwyn@smoke.BRL.MIL (Doug Gwyn) (08/13/89)

In article <186@ixi.UUCP> clive@ixi.uucp (Clive Feather) writes:
->    typedef
->    {     
->        t_all all;
->    }
->    t_whole;

Note: you're missing "struct" in these typedefs.

->(Q8)  Do the names of the common initial fields of t_all and t_first have to
->      be the same for this to work, or is it sufficient for the types to be
->      identical ?

Member types must match.  Member names don't matter.

->(Q9)  It seems to me that, since the union might only appear in one source
->      file, whilst the structures might be used in several, that the padding
->      of a structure depend *only* on the types of the fields of the
->      structure. Is this so ? If so, how do I get X3J11 to mandate it.

I don't understand the question.  I think you're asking how clever a compiler
is allowed to be with regard to struct padding.  The answer is, it must be
consistent across translation units with regard to the "common initial
members" requirement.

->(Q10) Do all the t_n_parts types have the same alignment requirements ? For
->      historical reasons, there are many functions which take an argument of
->      type t_1_parts, which is actually a value of one of the other types cast
->      correctly. These functions only access the part_1 fields.

The alignment of the t_n_part structure shouldn't matter, since you're using
a pointer to it and no padding is allowed at the beginning of a struct.  The
"common initial members" requirement does the rest of what you seem to need.

->(Q11) Can offsetof take "field1.field2" as its second argument ?

This doesn't seem to have been the intent of Standard section 4.1.5.

->(Q12) If not, can I add the offset of the sub-structure in the main one
->      and the field in the substructure to get the right effect ?
->      (I.e. can I use offsetof (T, field1) + offsetof (SUBT, field2)
->      to get the effect of offsetof (T, field1.field2).

Yes.

->(Q13) Does ANSI guarantee that, given the assertions in the various comments,
->      the call to memcpy will do the assignment ?

No, you're not allowed to perform pointer arithmetic on void*s.

->(Q14) If not, how do I write the last part of GetValue ?

Change your void*s to char*s.

lmb@ibmpa.UUCP (Larry Breed) (08/24/89)

In article <10724@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes:
>
>->(Q11) Can offsetof take "field1.field2" as its second argument ?
>
>This doesn't seem to have been the intent of Standard section 4.1.5.
>
Actually it was the intent.  Earlier drafts defined
	offsetof(type, identifier)  
where the identifier designated a member.  

The final draft defined
	offsetof(type, member-designator)
and says "... the member-designator shall be such that given
	static type t;
then the expression &(t.member-designator) evaluates to an address constant."
This change was made specifically to allow things like

	offsetof(struct fancy, inner_struct.a[10])

-- 
Larry Breed
inet: lmb%ibmsupt@uunet.uu.net
uucp: uunet!ibmsupt!lmb		(415) 855-4460