Path: utzoo!utgpu!jarvis.csri.toronto.edu!rutgers!cs.utexas.edu!csd4.milw.wisc.edu!uxc.cso.uiuc.edu!garcon!uicsrd.csrd.uiuc.edu!mcdaniel From: mcdaniel@uicsrd.csrd.uiuc.edu (Tim McDaniel) Newsgroups: comp.lang.c Subject: Re: struct accessing Message-ID: <1411@garcon.cso.uiuc.edu> Date: 4 Jul 89 06:01:16 GMT References: <1545@stl.stc.co.uk> <470002@gore.com> Sender: news@garcon.cso.uiuc.edu Reply-To: mcdaniel@uicsrd.csrd.uiuc.edu (Tim McDaniel) Organization: Center for Supercomputing R&D (Cedar), U. of Ill. Lines: 83 All bracketed references refer to a section in Appendix A of K&R, version 2. In article <470002@gore.com> jacob@gore.com (Jacob Gore) writes: >> Close, but no cigar. The pointer subtraction yields an error message, >> since &fred_proto is of type "struct fred *" and &fred_proto.tom is of >> type "int *". > >I suppose casting one into the other is non-portable? Generally, the only pointer-pointer casts that cause guaranteed results are casting an A* into a B* and back into an A*, which causes the final result to be equal to the starting value. However, B has to require less or equally strict storage alignment, and "alignment" is implementation-dependent (except that "char" has the least alignment restrictions). [6.6] There is a special dispensation, though: "If a pointer to a structure is cast to the type of a pointer to its first member, the result refers to the first member". [8.3] So int * mordecai; struct fred * haman; mordecai = (int *) &fred_proto; /* blessed */ haman = (struct fred *) &fred_proto.tom; /* cursed */ >> #define DICK (&fred_proto.dick - &fred_proto.tom) >> #define HARRY (&fred_proto.harry - &fred_proto.tom) >> Even if tom is the first int member of a struct fred, and all the int >> members are contiguous, it still isn't guaranteed to work. Pointer >> subtraction is defined by pANS C only over pointers into the same >> array. In particular, a compiler can put an arbitrary number of bytes >> of padding between struct members, and such padding wouldn't have to >> be a multiple of sizeof(int) bytes long. > >Why is the padding relevant? The only requirement is that a field's offset >is the same for all instances of the struct. "A non-[bit]field member of a structure is aligned at an addressing boundary dependent on its type; therefore, there may be unnamed holes in a strcture". [A8.3] Suppose pointer subtraction were permitted between structure members. Consider a sample storage layout for "struct fred" on some 32-bit machine: __ __ __ __ | __ __ __ __ | __ __ __ __ tom dick harry Since pointer subtraction yields "a signed integral value representing the displacement between the pointed-to objects; pointers to successive objects differ by 1" [7.7], DICK is 1 and HARRY is 2, and all is well with the Universe. But consider another possible storage layout: __ __ __ __ | xx xx __ __ | __ __ xx xx | __ __ __ __ tom dick harry where "x"s refer to "unnamed holes". Then DICK, which is (&fred_proto.dick - &fred_proto.tom) is ... what? 1.5? No, the result has to be an integer. But "dick" and "tom" are not separated by an integer multiple of "sizeof (int)" bytes. If the result of the subtraction is either 1 or 2, only half of "dick" would be accessed, and some undefined filler value would be brought along. "The value [of a pointer subtraction] is undefined unless the pointers point to objects within the same array" [7.7]. pANS C could have required that consecutive non-bitfield members of the same type have no padding between them, and it wouldn't be at all hard to implement on any architecture I can think of. I guess that nobody considered such a special case because nobody saw a need for it. The moral of the story is highly offensive: lbhe pbzcvyre'f vzcyrzragbe fubhyq chg uvf "ybat" qvpx arkg gb gbz naq uneel. Vs vg ehof ntnvafg "fubeg"f pbagnvavat na haanzrq ubyr, vg znl trg pubccrq va unys. -- "Let me control a planet's oxygen supply, and I don't care who makes the laws." - GREAT CTHUHLU'S STARRY WISDOM BAND (via Roger Leroux) __ \ Tim, the Bizarre and Oddly-Dressed Enchanter \ mcdaniel@uicsrd.csrd.uiuc.edu /\ mcdaniel%uicsrd@{uxc.cso.uiuc.edu,uiuc.csnet} _/ \_ {uunet,convex,pur-ee}!uiucuxc!uicsrd!mcdaniel