Address of array

Shack Toms jst at abic.UUCP
Wed Mar 5 16:39:31 AEST 1986


I have noticed that different compilers treat the & operator differently
when it is applied to arrays.  In particular, the UNIX compiler I have
been using warns against it.  K&R explicitly deny its legality.
However, the operation seems to me to be perfectly
reasonable when the desired result is a pointer to the array rather
than a pointer to the first element of the array.  For example,

typedef int foo[5];
foo x, y[3], *z;

if sizeof(int) == 4 then --
    sizeof *z == 20
    sizeof &**z == 4 if pointers are 4 bytes
    sizeof x == 20
    sizeof y[2] == 20
    sizeof **z == 4
    sizeof *x == 4
    sizeof *y[2] == 4
    z = &x is illegal although the types would match
    z = x is quasi-legal, the types mismatch, lint should complain
    z = &y[2] is illegal, for no good reason (my opinion)
    z = y + 2 is legal
    (int *) z == *z /* The pointer to array == pointer to first element */
    (int *) (z + 1) != *z + 1  /* But their types differ (with implications) */
    (int *) (y + 2) == y[2]
    y[2]+1 is a pointer to y[2][1]
    &y[2]+1 should be a pointer to y[3], but is illegal

The algorithms in question use z as a pointer to an array (usually)
within arrays.  It is useful sometimes to have z point to an isolated
array however.  The pointer increment operation (z++) is useful, so
it is desireable to not interchange the meanings of (pointer to array)
and (pointer to first element of array).

Where allowed in the language, an array name as an lvalue refers to
the entire array (e.g. sizeof) wheras an array name as an rvalue
evaluates to a constant pointer to the first element of the array.

Trying to use this to solve the problem, I create 'foo' as a struct
which contains the array as its sole field.  Then, when I want to access
the array as an lvalue, I use the struct name.  When I want to access
the array as an rvalue, I use the field name.

This ends up looking like:

typedef struct { int r[5]; } foo;
foo x, y[3], *z;

if sizeof(int) == 4 then --
    sizeof *z == 20
    sizeof &*(*z.r) == 4 if pointers are 4 bytes
    sizeof x == 20
    sizeof y[2] = 20
    sizeof *(*z.r) == 4
    sizeof *(x.r) == 4
    sizeof *(y[2].r) == 4
    z = &x now legal and produces the desired result
    z = x.r is just as quasi-legal as before
    z = &y[2] now legal and produces the desired result
    z = y + 2 is still legal
    (int *) z == *z.r /* The pointer to array == pointer to first element */
    (int *) (z + 1) != *z.r + 1/* But their types differ (with implications) */
    (int *) (y + 2) == y[2].r
    y[2].r+1 is a pointer to y[2].r[1]
    &y[2]+1 is a pointer to y[3], now is legal

This now does everything I would like with (y[2] = x) now being legal
as a bonus (on compilers which allow structure assignments.)  The problem
is that it is clumsy to have to keep writing .r whenever the array is
used as an rvalue.

Since the generalization of array references so that lvalues are
defined (and refer to the entire array) is useful, and is compatible
with the rest of the language definition, and is allowed in many
existing compilers... Why not make it official?

I am aware that this does not help with array assignments (as
'struct foo' does.)

Any comments?

Shack Toms @ Allen-Bradley

-- Is it warm in here, or is it just me?



More information about the Comp.lang.c mailing list