root@dsoft.UUCP (Super user) (11/08/88)
Maybe I've missed something in C, but One of the things I've never found a way
to do and have always wanted, was a precompiler command to allow me to use
the offset of an item into a structure. for example:
struct test {
long this;
int that;
char those[8];
};
val = offset(test,that);
As it is now, I have the choice to either recalculate the offset of a var in
a structure, or write it into the program source.
(EG: offs = &test.that - &test.this)
I find myself building massive structures and constantly moving the data around
within them, but I need to know the offset of certain variables to use as
key table entries in a keyed file system I wrote. I'd like to have a way
not to have to recalculate the offset into a structure every time I make
a change. It can get very harrowing at times!
Is there such a function already? or is there any plans for one?
ark@alice.UUCP (Andrew Koenig) (11/08/88)
In article <73@dsoft.UUCP>, root@dsoft.UUCP (Super user) writes: > Maybe I've missed something in C, but One of the things I've never found a way > to do and have always wanted, was a precompiler command to allow me to use > the offset of an item into a structure. for example: > struct test { > long this; > int that; > char those[8]; > }; > val = offset(test,that); C++ has it -- it's called a `pointer to member'. For example: struct test { long here; // `this' is a keyword in C++ int that; char those[8]; }; Now, you can declare `testp' to be a pointer to an (unspecified) int element of an (unspecified) test structure: int test::*testp; Of course in this example, there's only one member testp could possibly point to; let's make it point there: testp = &test::that; Now, let's declare a `test' object: test t; Finally, we'll set the field of t addressed by testp to 7: t.*testp = 7; To learn many more details about member pointers, see the paper by Lippman and Stroustrup in the proceedings of the 1988 USENIX C++ conference. -- --Andrew Koenig ark@europa.att.com
ok@quintus.uucp (Richard A. O'Keefe) (11/08/88)
In article <73@dsoft.UUCP> root@dsoft.UUCP (Super user) writes: >Maybe I've missed something in C, but One of the things I've never found a way >to do and have always wanted, was a precompiler command to allow me to use >the offset of an item into a structure. for example: This is one fo the things that has been easy to do for a long time. If you're using a UNIX(tm) system, you may already have a header file /usr/include/struct.h, which defines fldoff(Structure_TAG, Field_Name) fldsiz(Structure_TAG, Field_Name) Modulo parens: fldoff(Tag, Field) = ((int) &((struct Tag *)0)->Field) fldsiz(Tag, Field) = (sizeof ((struct Tag *)0)->Field) This may give trouble on some 80*86 C compilers. ANSI C will have an "official" offsetof macro. I couldn't find the file on a V.3 '386 system, but the macros worked fine.
klg@njsmu.UUCP (Kenneth Goodwin) (11/08/88)
In article <73@dsoft.UUCP>, root@dsoft.UUCP (Super user) writes: >was a precompiler command to allow me to use > the offset of an item into a structure. for example: > > struct test { > long this; > int that; > char those[8]; > }; > > val = offset(test,that); Until they actually stick something like this into the compiler , try this: #define offsetof(Struct, Member) (&((struct Struct *)0)->Member) I believe it;s parenthesized correctly. declares 0 to be a pointer of type struct Struct and computes the address of Member within the structure. since 0 + anything = anything what you get (obviously) is the offset of the member within the structure. Since all kludges have an inherent risk of non-portability comments on the above method are welcome. usage: value = offsetof(test, that); Ken Goodwin NJSMU.
crossgl@ingr.UUCP (Gordon Cross) (11/09/88)
In article <73@dsoft.UUCP>, root@dsoft.UUCP (Super user) writes: > Maybe I've missed something in C, but One of the things I've never found a > way to do and have always wanted, was a precompiler command to allow me to > use the offset of an item into a structure. for example: > > struct test { > long this; > int that; > char those[8]; > }; > > val = offset(test,that); Sure. Try this: #define offset(type,field) ((unsigned int)&((type *)0)->field) where "type" is the type of your struct (or union) and "field" is the name of the field you want the offset for. Any decent compiler should be able to evaluate this at compile time. For your example, you would use: val = offset (struct test, that); NOTE: if "unsigned int" is only 16 bits long on your implementation, you may want to use "unsigned long" to handle large structs like struct big { char buffer[70000]; int tail; }; val = offset (struct big, tail); Gordon Cross Intergraph Corp. Huntsville, AL
turner@sdti.UUCP (Prescott K. Turner) (11/09/88)
In article <73@dsoft.UUCP> root@dsoft.UUCP (Super user) writes: >Maybe I've missed something in C, but One of the things I've never found a way >to do and have always wanted, was a precompiler command to allow me to use >the offset of an item into a structure. > val = offset(test,that); ANSI C introduces the "offsetof" macro to do just what you ask. val = offsetof(test,that); C++ has a closely related feature called pointers to members. int test::*val = &test::that; ... test x; x.*val = 2; Here, val is not an int, but a more strongly typed thing which can be used only to point to offsets within a "struct test" that have type int. "offsetof" appears simpler and more flexible to me. The only rationale I can see for pointers to members is that they make pointers to member functions possible. And I wonder whether it might not have been better to find a way to use "offsetof" with member functions as well. Sorry, I don't know which C compilers already have "offsetof". -- Prescott K. Turner, Jr. Software Development Technologies, Inc. 375 Dutton Rd., Sudbury, MA 01776 USA (508) 443-5779 UUCP:...genrad!mrst!sdti!turner
mac3n@babbage.acc.virginia.edu (Alex Colvin) (11/11/88)
> > way to do and have always wanted, was a precompiler command to allow me to > > use the offset of an item into a structure. for example: > #define offset(type,field) ((unsigned int)&((type *)0)->field) This works by casting a pointer to an unsigned. That sometimes isn't a good idea. To make integers out of pointers, it's best to subtract. #define offset(type,field) ( (void *)&((type *)0)->field - (void *)((type *)0) ) This gives you the offset in (void)s. You could have it in (char)s or (short)s instead. The question is, why do you want this? It doesn't belong in the precompiler, since it has to know about size and alignment constraints. Explicit pointer subtraction is usually what I want.
chris@mimsy.UUCP (Chris Torek) (11/11/88)
>>#define offset(type,field) ((unsigned int)&((type *)0)->field) In article <399@babbage.acc.virginia.edu> mac3n@babbage.acc.virginia.edu (Alex Colvin) writes: >This works by casting a pointer to an unsigned. That sometimes isn't a >good idea. To make integers out of pointers, it's best to subtract. > >#define offset(type,field) ((void *)&((type *)0)->field - (void *)((type *)0)) The advice above is reasonable; the implementation is not. You may not perform arithmetic on pointers to void. This is considered a feature. The dpANS provides a (compiler-dependent!) macro called `offsetof' that might be defined as #define offsetof(t, f) ((char *)&((t *)0)->f - (char *)(t *)0) or more simply as #define offsetof(t, f) ((int)&((t *)0)->f) or as some horrible internal compiler reference: #define offsetof(t, f) __C_compiler_internal_label__offset_of(t, f) Various restrictions in the dpANS make all of these definitions suspect-at-best, but one (whatever it might be) is to be provided and called `offsetof'. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@mimsy.umd.edu Path: uunet!mimsy!chris
mick@auspyr.UUCP (Michael J. Andrew) (11/15/88)
In article <73@dsoft.UUCP> root@dsoft.UUCP (Super user) writes: |Maybe I've missed something in C, but One of the things I've never found a way |to do and have always wanted, was a precompiler command to allow me to use |the offset of an item into a structure. for example: | |struct test { | long this; | int that; | char those[8]; |}; | | val = offset(test,that); Try the following: #define OFFSET(structure,field) ((int) &(((struct structure *)0)->field)) A useful trick which I'm afraid I cannot take credit for. Watch out for hardware with brain damaged (read "clever") addressing! -- ------------------------------------------------------------------------- Michael Andrew Sr. Systems Engineer Austec, Inc. San Jose CA. mick@auspyr.UUCP or amdahl!auspyr!mick (408) 279 5533
throopw@xyzzy.UUCP (Wayne A. Throop) (11/17/88)
> klg@njsmu.UUCP (Kenneth Goodwin) > Until they actually stick [...offsetof...] into the compiler , try this: > > #define offsetof(Struct, Member) (&((struct Struct *)0)->Member) > > comments on the above method are welcome. Well, the type of the resulting expression is an address, not an integer offset in bytes, which is what I suppose is intended. Casting the above to int or unsigned isn't much help either, on word-oriented machines. So, there are two possible expressions involving addressing from the null pointer that are superior: #define offsetof(S,M) ((int)(char*)&(((struct Struct *)0)->M)) or, somewhat better #define offsetof(S,M) (((char*)&(((struct S)0)->M))-((char*)0)) The only way to improve on these (that I know of) in terms of portability is to actually allocate an example of S, and that can't be done purely from a macro. -- "Please, spare me, have mercy!" "Yes, that's it, beg, grovel. Now offer me riches, power, position." --- from "The Princess Bride" -- Wayne Throop <the-known-world>!mcnc!rti!xyzzy!throopw