[comp.sys.amiga.tech] Determining structure field offsets

jvkelley@watcgl.waterloo.edu (Jeff Kelley) (04/17/89)

What's the best way to determine the offset of a field of
a structure?  For example, if I have:
	struct foobar {
		int foo;
		int bar;
	};
how can I determine the offset of the 'bar' field in a
manner independent of preceding fields?  My initial
attempt was to use a macro of the form:
	#define STRUCT_OFFSET(structure, field) \
		((int)&((structure *)0)->field)
used like:
	offset = STRUCT_OFFSET(struct foobar, bar);

However, compiling with Lattice C 5.02 produces the Error
"Invalid structure reference" for this statement.  If the
0 in the macro is changed to something else, though,
such as a 1, no error is produced.  Of course, we have to
subtract 1 to compensate, so we get:
	#define KLUDGE 1	
	#define STRUCT_OFFSET(structure, field) \
		((int)&(((structure *)KLUDGE)->field)-KLUDGE)

This would be satisfactory (although I still don't
understand why 0 doesn't work) except that the compiler
produces pretty bad code, something like:
	movea.w	#1,a0
	lea	4(a0),a1
	move.l	a1,d0
	move.l	d0,d7		*
	subq.l	#1,d7
	move.l	d7,d0		*

(The two '*'ed statements are effectively eliminated by
 the 'global optimizer'.)

It seems to be a rather poor way of doing a
	moveq.l	#4,d0
which is generated by the GNU C compiler, at least when
KLUDGE is 0 (which doesn't produce an error with GNU C).
Couldn't the compiler do some expression tree analysis
and reduction?  Seeing code like this makes me want to
quit working as a programmer and take up fish-farming
in Alaska :-)

For an example of how this facility might be used, consider
a memory allocation scheme which records the size of the
memory allocated in the first longword of the allocated
block, then returns a pointer to the remainder to the user.
i.e. struct Block { long size; char user_area };
When the user calls 'free(block)' or whatever, in order to
find the block size you need to subtract the offset of
the user_area field from the pointer the user gives you.
Subtracting	'sizeof(long) ' or 'sizeof(block->size)'
doesn't cut it (in my opinion) because it doesn't track
changes to the structure.

Any and all help is appreciated.
--
Jeff Kelley    National Research Council of Canada, Ottawa
   uunet!watmath!watcgl!jvkelley  	tel:   (613) 990-5924

jafo@hpfcdc.HP.COM (Sean Reifschneider) (04/20/89)

>'sizeof' operator.  Wouldn't it be correct to use something like:
>
>	offset_to_second_field = sizeof(structure.first_field)

Only if you wanted the second element of the structure.  If there
are an unknown number of elements (0..n) in the structure:

	offset_to_N_field = pointer_to_N - pointer_to_structure

or:

	struct { int foo, bar; } *baz;
	long offset;

	offset = ((long) &baz->bar) - ((long) baz);

works.

Sean

bobb@tekfdi.FDI.TEK.COM (Robert Bales) (04/21/89)

In article <17372@cup.portal.com> FelineGrace@cup.portal.com (Dana B Bourgeois)
writes:

>Jeff Kelley wants to calculate the offset in a structure.

>Wouldn't it be correct to use something like:

>	offset_to_second_field = sizeof(structure.first_field)

There is often more than meets the eye to the size of structures. The start of
the structure will (almost certainly) be longword aligned, that is have an
address evenly divisible by 4. If "first_field" is a char, it will have sizeof
= 1. But if "second_field" is a long, it must be longword aligned (on the 
68000), and 3 padding bytes will be placed between the first two fields, with
the offset of the second being 4.

   Bob Bales
   Tektronix, Inc.

I help Tektronix make their instruments. They don't help me make my opinions.

jesup@cbmvax.UUCP (Randell Jesup) (04/21/89)

In article <38874@bbn.COM> cosell@BBN.COM (Bernie Cosell) writes:
>In article <11940@grebyn.COM> ckp@grebyn.COM (Checkpoint Technologies) writes:
>}
>}Someone asked about calculating structure member offsets in a portable
>}way.  You were close, but try this:
...
>You don't need the dummy variable: it is legal in C (although I don't know
>for ANSI C) to coerce the address '0' to be a pointer to anything.  And so
>        #define offset(s,f)       &(((s *)0)->f)
>works just fine.

	Lattice 5.02 has an offsetof() macro in stddef.h (where ANSI says
it should be).

-- 
Randell Jesup, Commodore Engineering {uunet|rutgers|allegra}!cbmvax!jesup