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