[comp.lang.c] Taking address of array

graham@tcom.stc.co.uk (Graham Bardsley) (04/10/91)

I've got some macros which calculate the address of an offset of a structure
(stolen from the X11R4 src), and some of the structures I'm using them have
character arrays:

struct small_struct
{
	int x;
	char y[100];
};

What I want to know is, if the macro calculates:

((int) (((char *) (&(((struct small_struct*) 0)->y))) - ((char *) 0)))

Is the value of this a valid construct which will calculate the offset of y on 
most traditional C compilers, since on the standard Sun C compiler it throws 
out the warning: 

	& before array or function: ignored

I think I'm just worried that a lot of compilers might throw it out as being 
bad C.  The macros are part of a portability layer so the idea is to have 
some macros which will work nomatter what compiler is being run. If the 
compiler doesn't support the offset macro directly (like ANSI) then 
something like the above will be substituted.





-- 
Graham Bardsley,NT Europe Ltd,Oakleigh Road South,New Southgate,London, N11 1HB
..{uunet,mcsun}!ukc!stc!graham   <graham@tcom.stc.co.uk>  Tel: +44 81 945 3799
And My long-winded ISO10021 address is probably something like:
G=/I=G/S=Bardsley/OU=lon4021/O=stc telecommunications/P=stc plc/A=gold 400/C=GB

marc@watson.ibm.com (Marc Auslander) (04/11/91)

In article <1991Apr9.172534.28982@tcom.stc.co.uk> graham@tcom.stc.co.uk (Graham Bardsley) writes:


>I've got some macros which calculate the address of an offset of a structure
>(stolen from the X11R4 src), and some of the structures I'm using them have
>character arrays:

>struct small_struct
>{
>	int x;
>	char y[100];
>};

>What I want to know is, if the macro calculates:

>((int) (((char *) (&(((struct small_struct*) 0)->y))) - ((char *) 0)))

>Is the value of this a valid construct which will calculate the offset of y on 
>most traditional C compilers, since on the standard Sun C compiler it throws 
>out the warning: 

>	& before array or function: ignored

The Risc System/6000 compiler also issues a warning message and
compiles.  

Note that if you have a macro which takes addresses of things and you
need to pass it an array, a work around is to pass the first element.
In your example:

 ((int) (((char *) (&(((struct small_struct*) 0)->y[0]))) - ((char *) 0)))

is correct C.
--


Marc Auslander       <marc@ibm.com>

steve@taumet.com (Stephen Clamage) (04/11/91)

graham@tcom.stc.co.uk (Graham Bardsley) writes:

>struct small_struct { int x; char y[100]; };

>((int) (((char *) (&(((struct small_struct*) 0)->y))) - ((char *) 0)))

>Is the value of this a valid construct which will calculate the offset of y on 
>most traditional C compilers...

The cast to char* and subtraction of zero don't do anything useful.

Casting the result to int is not appropriate on all systems.  ANSI uses
a defined type called 'size_t', which is the unsigned integral type of
the 'sizeof' operator (usually unsigned int, sometimes unsigned long).

A typical 'offsetof' macro looks like this:
	#define  offsetof(type, field) ((size_t)&(((type*)0)->field))

This, like your example, is not portable to all systems, since some will
object to what appears to be a dereference of a null pointer.

Your best bet might be to put something like this in common header:

#if __STDC__
#include <stddef.h>	/* ANSI C compiler, get correct size_t and offsetof */
#else
typedef unsigned int size_t;	/* or whatever type is correct */
#define offsetof(type, field) ((size_t)&(((type*)0)->field))
#endif
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com

torek@elf.ee.lbl.gov (Chris Torek) (04/12/91)

(this is all the result of X11 making a heroic effort to define `offsetof'
without using the ANSI `offsetof', even though the ANSI `offsetof' exists
precisely because it is not possible to define a portable `offsetof'...)

Given the X11R4 offsetof `approximation' macro
  #define offsetof(s, e) ((int)((char *)&((s *)0)->e - (char *)0))
(spelling mine---I took out all the `unnecessary' parentheses, and may
have changed the name itself [I prefer the ANSI `offsetof' name, since
people have to know what it means, these days]),

>In article <1991Apr9.172534.28982@tcom.stc.co.uk> graham@tcom.stc.co.uk
>(Graham Bardsley) writes:
>>struct small_struct {
>>	int x;
>>	char y[100];
>>};
>>[`offsetof(struct small_struct, y)' produces] the warning: 
>>	& before array or function: ignored

This simply means that you do not have an ANSI-conformant compiler
(no surprise, or you would not have to `make up' a nonportable offsetof
approximation---the X11 definition is the best one comp.lang.c has ever
seen, despite some previous article's advice to drop the `char *' casts
and the subtraction of `(char *)0').

In article <MARC.91Apr11082924@marc.watson.ibm.com>
marc@watson.ibm.com (Marc Auslander) writes:
>The Risc System/6000 compiler also issues a warning message and compiles.  

Sheesh, you guys are still shipping non-ANSI compilers? :-)

(Seriously, this particular glitch is trivial to fix in PCC, and probably
in most compilers: to allow &array you simply REMOVE one or two lines.
Everything else already works.  The compiler has to go out of its way
to reject &array.)

>Note that if you have a macro which takes addresses of things and you
>need to pass it an array, a work around is to pass the first element.

This will in fact always work wherever offsetof() works at all: the C
language effectively guarantees that

	offsetof(struct small_struct, y)

and

	offsetof(struct small_struct, y[0])

will produce the same value (provided this offsetof() works at all).

> ((int) (((char *) (&(((struct small_struct*) 0)->y[0]))) - ((char *) 0)))
>
>is correct C.

Correct syntactically, but its meaning is up to the compiler---that is why
offsetof() is not portable.
-- 
In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 415 486 5427)
Berkeley, CA		Domain:	torek@ee.lbl.gov

wolfram@cip-s08.informatik.rwth-aachen.de (Wolfram Roesler) (04/12/91)

graham@tcom.stc.co.uk (Graham Bardsley) writes:

>struct small_struct
>{
>	int x;
>	char y[100];
>};

>What I want to know is, if the macro calculates:

>((int) (((char *) (&(((s*) 0)->y))) - ((char *) 0)))

>Is the value of this a valid construct which will calculate the offset of y on 
>most traditional C compilers?

An & before an array fails on all compilers I know. In your example,
if s is of type small_struct, `s.y' is a pointer to the first element of
the array, and `&s.y' is illegal. Try `& s.y[0]' instead. I'm afraid
you will need to write a new macro, one that will determine the offset of
an array within a struct.
Suppose you used the macro

	#define offset(s,e) (int) (&(((s*)0)->e) - 0)

(parantheses and casts omitted for clarity) do determine the offset of
element e in struct s, you will have to write a new macro

	#define aoffset(s,e) (int) ((((s*)0)->e) - 0)
                                    ^
				    '&' omitted

if e is an array.
So: copy the original definition of your macro, give it a new name and
erase the '&' and use this one for arrays. This should work.

Grettings
Okami-san
f

gwyn@smoke.brl.mil (Doug Gwyn) (04/13/91)

In article <12010@dog.ee.lbl.gov> torek@elf.ee.lbl.gov (Chris Torek) writes:
>  #define offsetof(s, e) ((int)((char *)&((s *)0)->e - (char *)0))

If you have access to some structure of the desired type, which should
always be the case when using such a macro, you could add an argument
to take the structure for the base address, rather than playing
nonportable games with casts of "0".  The STD_C equivalent could
then just invoke offsetof() and ignore the extra structure argument.

steve@wattres.uucp (Steve Watt) (04/13/91)

In article <wolfram.671457523@cip-s08> wolfram@cip-s08.informatik.rwth-aachen.de (Wolfram Roesler) writes:
>graham@tcom.stc.co.uk (Graham Bardsley) writes:
>
>>struct small_struct
>>{
>>	int x;
>>	char y[100];
>>};
>
>>What I want to know is, if the macro calculates:
>
>>((int) (((char *) (&(((s*) 0)->y))) - ((char *) 0)))
>
>>Is the value of this a valid construct which will calculate the offset of y on 
>>most traditional C compilers?
[ slurp! ]
>element e in struct s, you will have to write a new macro

>	#define aoffset(s,e) (int) ((((s*)0)->e) - 0)
>                                    ^
>				    '&' omitted
[ and use this slightly different macro on the array elements ]

Ick.

My much preferred method is to simply say [0] in the invocation of the
macro:

#define offsetof(t,e)  ((size_t)(&(((s) *)0)->e))   /* probably over-parened */

char *p = buf + offsetof(myType, arrayStructMember[0]);
                                                  ^^^
Seems cleaner than having a *slightly* different macro, and also reminds you
that this element is *somewhat* special, but if you change it later, the
compiler is more likely to yell at you.
-- 
Steve Watt       steve@wattres.UUCP                  swatt@IBM.COM
          ...!decwrl!gigo!wattres!steve    ...!apple!claris!wattres!steve
Never trust a computer bigger than you can lift.