The Standard requires that for any type Foo
, the size of a Foo[N]
be exactly N * sizeof (Foo)
. It does not, however, specify any circumstances in which an object of type Foo[M][N]
(or even a Foo[N]
) may be accessed using an lvalue of type Foo
, unless Foo
happens to be a character type. Obviously it would be absurd to suggest that arrays of non-character type should not be accessible using subscript expressions, but the way N1570 6.5p7 is written doesn't actually allow that.
When using character types, the Standard seems to intend that a pointer to an object of size N
may be converted to character type and treated as though it were a char[N]
; functions like memcpy
and fwrite
rely upon such abilities. Still, the Standard doesn't explicitly say such a thing.
If one assumes that the intention of the Standard was to allow the elements of a Foo[M][N]
to be accessed using an lvalue of a non-character type Foo
in at least some circumstances, defining what those circumstances are would likely answer the question of when one may use a "flattened" pointer to access a multi-dimensional array.
Personally, I think that an lvalue D
which is derived from an lvalue of another type (e.g., given Foo myArray[10][12]; Foo *p = myArray[5];
, I would regard myArray[5]
as being an lvalue derived from myArray
, myArray[5][0]
as derived from myArray[0]
, and *p
as derived from myArray[5][0]
) should be usable to access storage within the object identified by the original, at least until either:
The same storage is accessed via some means not derived from D
.
An lvalue is produced that isn't derived from D
, that will be used to access that storage in conflicting fashion, or produce another lvalue that will be.
Code enters a loop or function wherein either of the above occurs.
Applying that principle, and treating a cast to an array-element type as "laundering" the exact type of the array, casting a Foo[M][N]
to a Foo*
would yield a pointer which could access all elements of the array as long as the array isn't accessed via any other means. A compiler that makes any bona fide effort to stay out of a programmer's way should have no trouble with such code. Unfortunately, the Standard doesn't specify any situations where compilers are required to allow derived lvalues to access parent objects, and some compiler writers interpret that as an invitation to ignore the possibility that lvalues might access storage associated with other lvalues from which they are derived.