From: msb@sq.sq.com (Mark Brader)
Subject: Re: struct hack, and other out-of-array references
Organization: SoftQuad Inc., Toronto, Canada
Date: Thu, 1 Oct 92 21:50:22 GMT

> : [Assuming a is a 2-dimensional array of ints whose 2nd dimension is y]
> : ... you can do
> :
> :       int *p = &a[x-1][y-1];
> :       p = (int *) ((char *) p + 2 * sizeof (int));
> :
> : and *p will now be a[x][1].  But you _cannot_ replace the second
> : statement with a simple "p += 2;" and expect the same result.  This
> : is the thrust of the Interpretation Ruling that was quoted earlier
> : in the thread.  You really have to make the excursion into char *
> : and back:  The standard requires that "a" be treatable as an array
> : of bytes, and therefore as an array of any character type, but not
> : as an array of int.
> 
> Sorry, but no. If you can treat it as an array of bytes, you can
> treat it as an array of *anything*, provided that you don't
> violate alignment restrictions.  That's the point of the rules on
> pointer casting and pointer arithmetic.

The rules on pointer arithmetic do NOT support indexing past subarrays.
Treating an object as an array of bytes is justified not by those rules
but by the definitions of "object" and "byte".

> (Alternately, if we were
> to imagine that your comment was true, there isn't anything
> special about the int* type; it would be equally illegal to index
> past the subarray with char* pointers.)

It isn't int* but char* that's special.
 
> : > In other words, these pointers are just pointers into an array,
> : > and correspond in the expected way to pointers into the doubly
> : > indexed array.
> :
> : They point to locations which are located as they would be in a
> : simple array, but the permitted operations are not the same.
> 
> The standard certainly doesn't say that and, as far as I know
> (not having the official interpretations, only Doug Gwyn's
> comments), the interpretation talks about indexing past
> subarrays, not about manipulating the converted pointers.

Indexing is not a primitive operation; pointer addition is.  There are
limits on what you can do with pointer addition which happen to be most
easily expressed in terms of indexing; to wit, if you declared "int k[5];"
then you can index k[0] through k[4] and you can construct, but not
indirect through, the pointer k+5.  This doesn't change if k is replaced
with a[i] for some i, and that's what the ruling is about.  Here is the
actual text that was posted earlier in the thread: the response to Request
For Interpretation 17, item 16.
 
||  For an array of arrays, the permitted pointer arithmetic in Standard
||  ##3.3.6 Semantics (page 48, lines 12-40) is to be understood by
||  interpreting the use of the word "object" as denoting the specific
||  object determined directly by the pointer's type and value, *not* other
||  objects related to that one by contiguity. For example, the following
||  code has undefined behaviour:
||      int a [4][5];
||      a [1][7] = 0;  /* undefined */
||  Some conforming implementations may choose to diagnose an "array bounds
||  violation", while others may choose to interpret such attempted accesses
||  successfully with the "obvious" extended semantics.

-- 
Mark Brader		  "Should array indices start at 0 or 1?  My ecumenical
SoftQuad Inc., Toronto	   compromise of 0.5 was rejected without, I thought,
utzoo!sq!msb, msb@sq.com   proper consideration."  -- Stan Kelly-Bootle

This article is in the public domain.
Newsgroups: comp.std.c