Path: utzoo!utgpu!jarvis.csri.toronto.edu!clyde.concordia.ca!uunet!mcsun!unido!mikros!mwtech!martin From: martin@mwtech.UUCP (Martin Weitzel) Newsgroups: comp.std.c Subject: Portable 'offsetof()' (was: Void pointers and pointer arithmetic) Message-ID: <582@mwtech.UUCP> Date: 16 Jan 90 21:23:19 GMT References: <1055@esatst.yc.estec.nl> <1990Jan3.073624.14061@twwells.com> <1421@sas.UUCP> Reply-To: martin@mwtech.UUCP (Martin Weitzel) Organization: MIKROS Systemware, Darmstadt/W-Germany Lines: 75 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@mwtech.UUCP, voice: 49-(0)6151-6 56 83