Two standards problems

david.f.prosser dfp at cbnewsl.ATT.COM
Tue Jun 20 07:04:32 AEST 1989


In article <186 at ixi.UUCP> clive at ixi.uucp (Clive Feather) writes:
}In article <183 at 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 at ixi.uucp
}...!uunet!ukc!ixi!clive (riskier)

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



More information about the Comp.std.c mailing list