Citing from WG14/N1124 Committee Draft May 6, 2005 ISO/IEC 9899:TC2
6.2.5 Types
[22] An array type of unknown size is an incomplete type. It is
completed, for an identifier of that type, by specifying the size in a
later declaration (with internal or external linkage).
extern char arr[];
shall be an incomplete type.
6.5.2.1 Array subscripting
[2] A postfix expression followed by an expression in square brackets
[] is a subscripted designation of an element of an array object. The
definition of the subscript operator [] is that E1[E2] is identical to
(*((E1)+(E2))). Because of the conversion rules that apply to the
binary + operator, if E1 is an array object (equivalently, a pointer
to the initial element of an array object) and E2 is an integer,
E1[E2] designates the E2-th element of E1 (counting from zero).
func(arr[7]); /* or func(7[arr]); */
is identical to
func( *(arr + 7) ); /* Memory for arr allocated in other module; */
6.7.5.2 Array Declarators
[4] If the size is not present, the array type is an incomplete type.
[8] EXAMPLE 2 Note the distinction between the declarations
extern int *x;
extern int y[];
The first declares x to be a pointer to int; the
second declares y to be an array of int of unspecified size (an
incomplete type), the storage for which is defined elsewhere.
x is complete because sizeof x is known. y is incomplete because size of y is unknown while compiling this unit.
extern char arr[];
is not identical to
extern char *arr;
Footnote[92]
If prior invalid pointer operations (such as accesses outside array
bounds) produced undefined behavior, subsequent comparisons also
produce undefined behavior.
Annex J.2 Undefined behavior
— An array subscript is out of range, even if an object is apparently
accessible with the given subscript (as in the lvalue expression
a1[7] given the declaration int a[4][5]) (6.5.6).
— Addition or
subtraction of a pointer into, or just beyond, an array object and an
integer type produces a result that points just beyond the array
object and is used as the operand of a unary * operator that is
evaluated (6.5.6).
Compiler is expected to generate code to access 7th element of arr
(0-based) and if definition of arr
does not contain 7+1
i.e. 8 elements or more, behavior shall be undefined. But code would be compilable and would exhibit well defined behavior as long as linked arr
has sufficient size.