Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10.2 9/17/84; site abic.UUCP Path: utzoo!linus!decvax!cwruecmp!abic!jst From: jst@abic.UUCP (Shack Toms) Newsgroups: net.lang.c Subject: Address of array Message-ID: <750@abic.UUCP> Date: Wed, 5-Mar-86 01:39:31 EST Article-I.D.: abic.750 Posted: Wed Mar 5 01:39:31 1986 Date-Received: Sat, 8-Mar-86 07:33:33 EST Organization: Allen-Bradley Co., Highland Heights, OH 44143 Lines: 84 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?