Portable 'offsetof()' (was: Void pointers and pointer arithmetic)

Martin Weitzel martin at mwtech.UUCP
Wed Jan 17 08:23:19 AEST 1990


There was a recent discussion about a portable version on the
ANSI-C 'offsetof()'-Makro. (This Makro can be used, to determine
the distance of a structure member to the beginning of the struct.)

Look at the following C-Structure:

	static struct {
		...............
		anytype m;
		...............
	} s;

In general, there should be no problem with the following

	(char *)&s.m - (char *)&s

except, that most compilers must evaluate this at run time,
hence you may not use it at compile time, which is sometimes
desirable for efficiency reasons or for defining a memory
region (char array) capable of containing all bytes of "s"
upto "m".

Evaluating this expression at compile time would require two
relocations to the result - if the compiler does not notice,
that both would cancel out each other (most compilers do
*not* detect this.). On the other side, most object file
formats are designed to handle no more than *one* relocation
in their symbol tables. (IMHO ANSI-C honors that prohibiting
more than one relocatable adress in a compile time constant.
Maybe, the committee also noticed a need for this special
case and invented the 'offsetof()'-Makro.)

Though it seems not possible to write a portable version of
'offsetof()' it is possible to have a portable *solution*
to the real problem behind it. It requires three steps:

1) Use named constants (#define-s) in all places, where
   you need the offset of a structure member.

2) Write a small program which automatically generates
   a header file, you #include into all sources, which
   needs to know the offset. There is no difficulty to
   write this generating program in a portable way (see
   above.)

3) Modify your Makefiles to compile and run the generating
   program before any of the sources, that include the
   generated header. (This too is not difficult, but be
   sure *never* to copy the generated header, when you
   move your sources from one system to an other!)

BTW: The general idea behind this approach provides a
solution for a certain class of problems, that is defined
as follows: 

	"You need an information, that depends
	on the target environment at compile time,
	but it is less difficult and/or more portable
	to get to this information at run time."

Some problems, which fall into that class, are:

- size (in Bits) of the basic types;
- behaviour of "plain" chars (signed/unsigned)
  and behaviour of right shifts;
- the most accurate value of PI (= 2*acos(0.0))

Some refinements of this technique also allow for automatical
optimizations. Eg. on a System without FPU it might desirable
to substitute an integer work around for some trivial floating
point calculations. Here the generating progam could obtain
the timing for both alternatives and produce a #define, which
is in the 'real source' used to select the best alternative.
-- 
Martin Weitzel, email: martin at mwtech.UUCP, voice: 49-(0)6151-6 56 83



More information about the Comp.std.c mailing list