[comp.lang.c] Something new for C?

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