James Kuyper said:
Tim Rentsch wrote:
...
A plausible analysis, but not on point, since the example code
above doesn't cast array[1], it casts array, which allows access
to the whole object.
Citation, please - where does the standard say that such a conversion
allows access to the whole object? Where, in fact, does the standard say
anything at all about what you can do with the converted pointer value,
other than convert it back to it's original type?
Which view is more reasonable:
A. Pointer conversion yields a pointer to the same object as
the original (assuming no alignment problems); or
B. Pointer conversion follows a strict constructionist view -
the only thing you can do with a converted pointer is
convert it back to the original type and compare it against
the unconverted original (assuming non-char types, etc)?
Of course, no one really believes (B); if they did, then they
should insist that a code sequence like
int i = 0;
const int *p = &i;
return *p;
produces undefined behavior.
Are you advocating a strict constructionist interpretation along
the lines of B? If not, then what interpretation are you
advocating?
My argument depends only upon the type of the pointer, not on the
sequence of conversions that produced that pointer value.
What I think you mean is that your rule about what's allowed
depends only on the type of the pointer, although whether that's
the type before conversion or after conversion I'm not sure.
Surely your argument depends at least in part on what is said in
the standard. Can you better articulate what your position is?
Spot on!
I believe that this is covered by the standard's promises that "The
pointer returned if the allocation succeeds is suitably aligned so that
it may be assigned to a pointer to any type of object and then used to
access such an object or an array of such objects in the space allocated
(until the space is explicitly deallocated)."
So you're changing your previous position that arrays exist only
where there are array declarations?
I do not agree that this provides general permission to treat any
arbitrary sequence of 'int's as an array just because they happen to
occupy memory in the same way that they would if they were declared as
an array of int.
You're doing a better job of saying what you think the rules
aren't than saying what you think the rules are.
Or, how about this:
int flat[15];
int (*not_flat)[3] = (int (*)[3])flat;
Since the only array object declared here is flat, by your
reasoning an access like not_flat[2][4] should be legal.
The result of the conversion you performed there is not specified by the
standard; the only thing that the standard guarantees about that
converted pointer value is that, if you convert it back to the original
type, it will compare equal to the original pointer.
What is certainly true is that the standard guarantees AT LEAST
that the value of not_flat can be converted back to int* and
compare equal to flat (with the usual disclaimer about
alignment). The question is, does it guarantee anything else,
and if so what? If you want to adopt a strict constructionist
interpretation, along with the consequences of that, well, to
each his own. I think most people believe that interpretation
is not really sensible as regards pointer conversion.
What I think most people believe, and what the standard says
(somewhat poorly) and also intends, is this:
1. If (e) is an expression of array type, then &(e)
is a
pointer that allows access to all elements in the array object
designated by (e); this array object is limited by both the
number of elements in the array type (if it's a complete type)
and the extent of the outermost containing object, and of course
i must be an allowed index for that range.
2. Assigning a pointer value of the same type, or computing a new
pointer value based on pointer arithmetic, produces a new pointer
value with the same byte range as the original pointer.
3. Converting a pointer value produces a new pointer value that
points to the same object as, and has the same byte range as, the
orginal pointer (with the usual alignment disclaimer).
4. A pointer derived from the result of doing a malloc(N) is the
same as converting from a pointer value *(char(*)[N])malloc(N)
(here of course malloc guarantees no alignment problems).
I believe these are correct because they are most consistent with
everything the standard says about what a pointer is, what arrays
are, what conversion is, how pointer arithmetic works, what may
be expected for multi-dimensional array objects, and the rules
for effective type and object access, among others. If have a
different opinion, that's fine, but please suggest a set of rules
covering the cases included in 1-4 that offer a more consistent
viewpoint than the one given here.