Variable Length Array Proposal
Tom MacDonald
uunet!tamarack.cray.com!tam
Tue Feb 2 20:59:21 PST 1993
Below is a cover letter and a proposal for a Varaible Length Array
type that X3J11.1 (Numerical C Extensions Group) is currently
debating. If you are interested in receiving a formatted version
on paper, please send me Email and I'll mail you one. Previously
paper copies of proposals were sent to these organizations. I'm
trying this Email method to see how effective it is. Thanks.
Tom MacDonald (tamacray.com)
============= Cover Letter ========== Cover Letter ==============
To: Members of X3J11, WG14, X3J16, WG21, and X3H5
From: X3J11.1
Topic: Comments on Variable Length Array (VLA) Proposal by
the VLA Subgroup
Date: January 22, 1993
The X3J11.1 committee is chartered to explore additional
features that will make C a better language for numeric and
scientific programming. We are not producing a standard,
but rather a technical report that can be used by X3J11 and
WG14 as guidance for a future standard, and by vendors who
wish to keep pace with the state of the art in C language
development. The addition of a Variable Length Array (VLA)
type to C was identified by X3J11.1 as being an important
issue for numeric and scientific programmers.
At a recent X3J11.1 meeting (7-8 December 1992), voting
members recommended that two competing proposals be sent to
a wider audience for comments. X3J11.1 hopes to get addi-
tional input, personal preferences, and further guidance
from other interested groups on both proposals. The vote to
send out these proposals was: 10 Yes, 1 Yes with comment, 2
No, and 2 Undecided.
This proposal is one of the competing proposals and is
titled, ``Arrays of Variable Length.'' The other proposal
is being distributed separately. Please send your comments
to the author, Tom MacDonald, whose name and Email address
appear on the proposal. Response by Email is preferred. We
need to receive your comments by April 1, 1993. All of your
comments on this proposal will be collated, and the results
will appear in a future revision of the proposal.
There is an existing implementation by Cray Research, Inc.
of this proposal. Please feel free to comment on all parts
of the proposal. Specifically, we would appreciate receiv-
ing comments about the following key points:
- The typing system of C has been enhanced to permit the
declaration of arrays whose size is determined at execu-
tion time. These array types are called VLA types.
Only identifiers with automatic storage duration can
have a type that contains a VLA type. Furthermore,
structure and union members cannot have VLA types. Is
this an acceptable limitation?
- For function prototypes, this proposal allows an iden-
tifier that is declared as a parameter and appears in an
array size expression to have its scope extended to the
beginning of the parameter-type-list (rather than begin-
ning just after the completion of its declarator). An
example is:
void func(int a[n][n], int n) { ... }
in which the parameter n is used to specify the size of
the VLA type. This is intended to allow the use of a
prototype in a definition and avoid forcing the use of
an ``old-style'' definition such as:
void func(a,n)
int n;
int a[n][n];
{ ... }
to accomplish the same ordering. Is this fundamental
change to C's lexical ordering within a prototype
acceptable?
- When the operand of a sizeof operator has a VLA type,
the operation cannot be used anywhere a constant expres-
sion is required. A sizeof operator can still be used
in constant expressions if its operand does not have a
VLA type. Is this addition to the semantics of sizeof
acceptable?
Thank you for your time and effort.
========= Delete this line and everything above before printing ========
Arrays of Variable Length
(Revision 9)
X3J11.1/93-007
Tom MacDonald
Cray Research, Inc.
655F Lone Oak Drive
Eagan, MN 55121
tamacray.com
January 22, 1993
ABSTRACT
The inability to declare arrays whose size is
known only at runtime is often cited as a primary
deterrent to using C as a numerical computing
language. Arrays of this nature are implemented
in the current GNU-C and Cray Research C com-
pilers. The adoption of GNU-C's treatment of
variable length arrays was proposed to the X3J11
Committee that defined the ANSI C and ISO C stan-
dards, but was dismissed as having too many far-
reaching implications. Eventual adoption of some
standard notion of runtime arrays is considered
crucial for C's acceptance as a major player in
the numerical computing world. This paper
describes an implementation of variable length
arrays which Cray Research has chosen for its
Standard C Compilers (SCC), with the intent that
the more prior art in this area, the more likely
it will appear in a future C standard.
Introduction
This is Cray Research's proposal for Variable Length
Array (VLA) types. Insertion of this new array type into
the existing Standard for C requires an examination of each
section of the existing Standard with necessary elaboration
for those sections which appear to be impacted. Accord-
ingly, the numbering, titles and general format of each of
the following several paragraphs match those found in the
current C Standard. The ISO section numbers are listed
first, followed by the corresponding ANSI section numbers in
- 1 -
1/22/93 Arrays of Variable Length X3J11.1/93-007
parentheses. If a paragraph is meant to address definitive
issues relating to variable length arrays, then an overview
of these issues appears followed by a brief rationale sec-
tion detailing Cray Research's current approach.
6.1.2.4 (3.1.2.4) Storage Duration of Objects
An object whose identifier is declared with no linkage
and without the storage-class specifier static has automatic
storage duration. Storage is guaranteed to be reserved for
a new instance of such an object on each normal entry into
the block with which it is associated. If the block with
which the object is associated is entered by a jump from
outside the block to a labeled statement in the block or in
an enclosed block, then storage is guaranteed to be reserved
provided the object does not have a variable length array
type. If the object is variably qualified and the block is
entered by a jump to a labeled statement, then the behavior
is undefined. If an initialization is specified for the
value stored in the object, it is performed on each normal
entry, but not if the block is entered by a jump to a
labeled statement. Storage for the object is no longer
guaranteed to be reserved when execution of the block ends
in any way. (Entering an enclosed block suspends but does
not end execution of the enclosing block. Calling a func-
tion suspends but does not end execution of the block con-
taining the call.) The value of a pointer that referred to
an object with automatic storage duration that is no longer
guaranteed to be reserved is indeterminate.
Forward reference: variably qualified (6.5), (3.5), vari-
able length array (6.5.4.2), (3.5.4.2).
6.3.3.4 (3.3.3.4) The sizeof operator
Semantics
When applied to an operand that has array type, the
result is the total number of bytes in the array. For vari-
able length array types the result is not a constant expres-
sion and is computed at program execution time.
Forward reference: variable length array (6.5.4.2),
(3.5.4.2).
- 2 -
1/22/93 Arrays of Variable Length X3J11.1/93-007
Example 1
int i = 2, j = 3, k, koo;
int *p = &i;
int func(int n) {
char b[*p==n ? k = j++ : n+j]; /* side effects OK */
return (sizeof(b)); /* runtime expression */
}
main() {
koo = func(10); /* runtime sizeof; koo == 13 */
}
ISSUE
Overview:
The sizeof operator could previously be used in any
constant expression (except those associated with preproces-
sor directives such as #if). With this extension to the
language, such is no longer the case since runtime code must
be generated to calculate the size of a variable length
array type.
Rationale:
The notion of ``size'' is an important part of such
operations as pointer increment, subscripting, and pointer
difference. Although the sizeof operator will now produce a
value computed at runtime, there still exists a consistency
when applied to the previously mentioned operations. Furth-
ermore, it can still be used as an operand to the malloc
function and to compute the number of elements in an array.
6.4 (3.4) Constant Expressions
Semantics
An integral constant expression shall have integral
type and shall only have operands that are integer con-
stants, enumeration constants, character constants, sizeof
expressions whose operand does not have a variable length
array type, and floating constants that are the immediate
operands of casts. An arithmetic constant expression shall
have arithmetic type and shall only have operands that are
integer constants, floating constants, enumeration con-
stants, character constants, and sizeof expressions whose
operand does not have a variable length array type.
- 3 -
1/22/93 Arrays of Variable Length X3J11.1/93-007
6.5 (3.5) Declarations
Semantic
If the sequence of specifiers in a declarator contains
a variable length array type, the type specified by the
declarator is said to be variably qualified.
Forward reference: variable length array (6.5.4.2),
(3.5.4.2).
6.5.2 (3.5.2) Type Specifiers
Contraint
Only identifiers with block scope can have a variably
qualified type. Objects with static storage duration shall
not be declared with a variably qualified type. Only ordi-
nary identifiers (as defined in 6.1.2.3 (3.1.2.3)) may be
declared with a variable length array type.
Forward reference: variable length array (6.5.4.2),
(3.5.4.2).
ISSUES
Overview:
This section discusses two issues about declarations
containing variable length array specifiers (i.e., VLAs).
First, VLAs must be declared at either block scope or func-
tion prototype scope, and must have automatic storage dura-
tion (i.e., no static storage duration objects). This means
that file scope variables and variables declared with the
static storage class specifier, can never be variably quali-
fied objects of any fashion. Second, if the identifier that
is being declared has a variable length array type (as
opposed to a pointer to an array), then it must be an ordi-
nary identifier.
- 4 -
1/22/93 Arrays of Variable Length X3J11.1/93-007
Example 2
extern int n;
struct { int (*z)[n]; }; /* Error - file scope member pointer to VLA */
int A[n]; /* Error - file scope VLA */
static int (*p)[n]; /* Error - file scope pointer to VLA */
int B[100];
void func(int m, int C[m][m]) {/* OK - prototype VLA */
struct { int (*y)[n]; /* OK - block scope member pointer to VLA */
int z[n]; }; /* Error - z is not an ordinary identifier*/
int D[m]; /* OK - auto VLA */
static int E[m]; /* Error - static block scope VLA */
int (*s)[m]; /* OK - auto pointer to VLA */
extern int (*r)[m]; /* Error - pointer to VLA with linkage */
static int (*q)[m] = &B; /* Error - static pointer to VLA */
}
Rationale:
Restricting variable length array declarators to iden-
tifiers with automatic storage duration is natural since
``variableness'' at file scope requires some notion of
parameterized typing. Previous versions of this proposal
permitted block scope static pointers to VLAs. They have
been removed from this version because there appears to be
no utility for them. If a use is identified, they are not
difficult to add back into a later proposal.
6.5.2.1 (3.5.2.1) Structure and Union Specifiers
Contraint
A structure or union shall not contain a member with a
variable length array type.
Forward reference: variable length array (6.5.4.2),
(3.5.4.2).
ISSUES
Overview:
This issue involves the declaration of members of
structures or unions with variably qualified types. To
allow this engenders a host of problems such as treatment
when passing such objects (or even pointers to such objects)
as parameters. In addition, the offsetof macro would
require extended meaning, to wit:
- 5 -
1/22/93 Arrays of Variable Length X3J11.1/93-007
Example 3
int n = 8;
main() {
struct tag {
int m1;
int m2[n]; /* not allowed by this proposal */
int m3;
};
int i;
i = offsetof(struct tag, m1); /* OK */
i = offsetof(struct tag, m2); /* OK */
i = offsetof(struct tag, m3); /* undefined behavior? */
}
Since the expansion of offsetof is implementation specific,
it seems impractical to guarantee any behavior for members
which might follow a variable length array type member.
Finally, any structure or union containing a variable length
array type must not be declared at file scope due to its
variable nature. This forces every user to re-specify the
structure type inside each function, and raises type compa-
tibility questions. Allowing formal arguments to be struc-
tures with variable length array type members (as well as
pointers to same) was problematic and, since functions could
not return them either, the utility of the whole exercise
centered around stack allocated structures with variable
length members. Objects of this sort are narrowly focused
and thus the decision was made to disallow the variable
length array type within structures and unions.
If all ordinary identifiers found in the arbitrary size
expressions of a given member were compelled to resolve to
other members of the same structure or union, then some
utility could be found in allowing structures and unions to
have variably qualified members. Such members would become
self-contained ``fat pointers'' of sorts. The following
example demonstrates this concept:
Example 4
struct tag {
int n; /* initialized to 5 */
int m2[n]; /* uses member `n' to complete size */
} x = { 5 };
The possibility of resolving the size of variable length
array members amongst other members could be explored.
There were two votes taken at NCEG meeting #5 in Norwood,
MA, which asked the following questions:
Q: Should there be some way to declare a VLA member
Yes: 11 No: 1 Undecided: 4
- 6 -
1/22/93 Arrays of Variable Length X3J11.1/93-007
Q: In favor of type shown in Example 3? 3
Q: In favor of type shown in Example 4? 6
Q: Undecided? 7
There is considerable sentiment for adding VLA members but
it appears the implications of each approach needs to be
explored before the committee can reach consensus. This
proposal has elected to pursue VLAs outside of structures
and unions. A future proposal may attempt to resolve the
VLA issue for members.
6.5.4 (3.5.4) Declarators
6.5.4.2 (3.5.4.2) Array declarators
Constraints
The [ and ] shall delimit an expression or *. If [ and
] delimit an expression (which specifies the size of an
array), it shall be an integral type. If the expression is
a constant expression then it shall have a value greater
than zero.
Semantic
If, in the declaration ``T D1,'' D1 has the form
D[assignment-expression "opt"]
or
D[*]
and the type specified for ident in the declaration ``T D''
is ``derived-declarator-type-list T,'' then the type speci-
fied for ident in ``T D'' is ``derived-declarator-type-list
array of T.'' If the size expression is not present the
array type is an incomplete type. If * is used instead of a
size expression, the array type is a variable length array
type of unspecified size, which can only be used in declara-
tions with function prototype scope. If the size expression
is a constant expression and the element type has a fixed
size, the array type is a fixed length array type. Other-
wise, the array type is a variable length array type. If
the size expression is not a constant expression, it is
evaluated at program execution time, it may contain side
effects, and shall evaluate to a value greater than zero.
For two arrays types to be compatible, both shall have
compatible element types, and if both size specifiers are
present and constant, then both size specifiers shall have
the same constant value. If either size specifier is vari-
able, the two sizes must evaluate, at program execution
- 7 -
1/22/93 Arrays of Variable Length X3J11.1/93-007
time, to equal values. It is undefined behavior if the two
size specifiers evaluate to unequal values at execution
time.
Example 5
extern int n;
extern int m;
main() {
int a[n][6][m];
int (*p)[4][n+1];
int c[n][n][6][m];
int (*r)[n][n][n+1];
p = a; /* error - not compatible because 4 != 6 */
r = c; /* compatible - assume n == 6 at execution time */
/* assume m==n+1 at execution time */
}
Example 6
int dim4 = 4;
int dim6 = 6;
void func() {
int (*q)[dim4][8][dim6];
int (*r)[dim6][8][1];
r = q; /* compatible, but undefined behavior at runtime */
}
ISSUES
Overview:
An issue raised by this section concerns type compati-
bility and the fact that variably qualified types are not
fully specified until execution time. Is that when compati-
bility checks should occur? Should the checks be mandatory?
Finally, the presence of possible side-effects in type
declarations is new. Since side effects include volatile
variables there seems to be no compelling reason to forbid
side effects in variable length array size specifiers.
Rationale:
The language chosen by Cray Research reflects a ``path
of least resistance'' approach. The `undefined behavior'
paradigm is invoked if things do not match up at runtime as
they normally would for fixed length arrays. Prototype
side-effects are handled with a syntactic option (see use of
[*] in section 6.5.4.3 (3.5.4.3) below) and by inhibiting
expression evaluation until function definition time.
- 8 -
1/22/93 Arrays of Variable Length X3J11.1/93-007
6.5.4.3 (3.5.4.3) Function Declarators (Including Prototypes)
Semantics
For each parameter declared with variable length array
type, the type used for compatibility comparisons is the one
that results from conversion to a pointer type, as in 6.7.1
(3.7.1). In a function prototype declarator that is not
part of a function definition, the syntax [*] may be ued to
pecify a variable length array type. In a parameter-type-
list, if an identifier is both declared as a parameter and
appears in an array size expression that is not a constant
expression, then the scope of that identifier is extended to
the beginning of the parameter-type-list (rather than begin-
ning just after the completion of its declarator). If the
size of a variable length array depends upon the size of
itself, or another variable length array declared in the
same parameter-type-list, then the behavior is undefined.
Example 7
/* Following prototype has a variably qualified parameter */
void addscalar(int n, int m, double a[n][n*m + 300], double x);
double A[4][308];
main() {
addscalar(4, 2, A, 3.14);
}
void addscalar(int n, int m, double a[n][n*m + 300], double x) {
int i,j,k=n*m+300;
for (i=0; i<n; i++)
for (j=0; j<k; j++)
a[i][j] += x; /* `a' is pointer to a VLA
of size: n*m + 300 */
}
Example 8
/* The following are compatible function prototype declarators: */
void matrix_mult(int n, int m, double a[n][m], double b[m][n], double c[n][n]);
void matrix_mult(int n, int m, double a[*][*], double b[*][*], double c[*][*]);
void matrix_mult(int n, int m, double a[ ][*], double b[ ][*], double c[ ][*]);
void matrix_mult(int n, int m, double a[ ][m], double b[ ][n], double c[ ][n]);
- 9 -
1/22/93 Arrays of Variable Length X3J11.1/93-007
Since the order in which parameters are specified is unim-
portant, the following compatible function prototypes are
functionally equivalent to the above four prototypes in that
the value of parameters n and m are used to complete the
variable length array modifiers.
void matrix_mult(double a[n][m], double b[m][n], double c[n][n], int n, int m);
void matrix_mult(double a[*][*], double b[*][*], double c[*][*], int n, int m);
void matrix_mult(double a[ ][*], double b[ ][*], double c[ ][*], int n, int m);
void matrix_mult(double a[ ][m], double b[ ][n], double c[ ][n], int n, int m);
The following atypical program shows that the meaning of
existing programs is preserved. The enumeration constant n
is used in the array size expression because the size is a
constant expression.
Example 9
enum { n = 5 };
/* enum constant `n' used instead of parameter `n' */
void f1(int a[][n], int n) {}
The following atypical program is not currently standard
conforming because the parameter x declared in function func
is a VLA. In this case the scope of parameter t is extended
to the beginning of the parameter list.
Example 10
enum {r=3, s=4, t=5};
float a[6][6];
void func(int, float [][*], int);
main() {
func(4, a, 2); /* need ptr to 6 element array */
}
/* parameter `t' used instead of enum constant `t' */
void func(int n, float x[][n+t], int t) {
printf("%s\n",
sizeof(*x)==sizeof(float [6]) ? "OK" : "Compiler error");
return;
}
The following function declarator contains an error because
the array sizes of parameters p and q depend upon the size
of a VLA declared within the parameter-type-list.
- 10 -
1/22/93 Arrays of Variable Length X3J11.1/93-007
Example 11
/* error - p and q use VLA sizes of parameters */
int func(int (*p)[sizeof(*q)], int (*q)[sizeof(*p)]) { ... }
In the following function prototypes, the parameter n is
used to complete the variable length array types. The file
scope variable n is never referenced.
Example 12
extern int n; /* file scope variable is never referenced!! */
void f(double a[][n], int n) { /* ... */ }
extern int m; /* file scope variable */
void g(double b[][n*m], int n) { /* ... */ }
The following example is also acceptable. The parameter n
is used to complete the VLA size expression.
Example 13
extern int n;
void g(int n, int a[][n]) { /* OK */
/* ... */
}
ISSUES
Overview:
By far the most controversial issue involves the ``lex-
ical ordering problem'' that is presented when prototypes
with variably qualified parameters are used and the size
expression involves an identifier that is not visible.
Currently, programmers do not need to concern themselves
with the order in which formal parameters are specified, and
one common programming style is to declare the most impor-
tant parameters first. Consider the following prototype
definition:
- 11 -
1/22/93 Arrays of Variable Length X3J11.1/93-007
Example 14
/* prototype declaration for old-style definition */
void f(double a[*][*], int n);
void f(a, n)
int n;
double a[n][n];
{
/* ... */
}
The order in which the names are specified in the parameter
list does not depend on the order of the parameter declara-
tions themselves. The accompanying prototype declaration is
compatible with this definition and thus it seems appropri-
ate to allow the following prototype definition in lieu of
the previous old-style definition.
Example 15
void f(double a[n][n], int n) {
/* ... */
}
With current lexical ordering rules the declaration of a
would force n to be undefined or captured by an outside
declaration; but in no case would the parameter n be used as
the programmer clearly intends. This is an unforeseen
side-effect of Standard C prototype syntax. The following
vote that was taken at NCEG meeting #5 in Norwood, MA, about
the importance of preserving lexical ordering.
In favor of preservation of lexical ordering? 4
In favor of more relaxed rules? 4
Undecided? 7
At X3J11.1 meeting #1 in Cupertino, CA, a proposal was made
to require a permutation such that all identifiers in size
expressions must associate with a visible definition, and
that no two permutations result in different associations.
This same vote was taken again:
In favor of preservation of lexical ordering? 7
In favor of more relaxed ordering? 7
Undecided? 2
This approach introduced its own set of issues and did not
significantly affect the vote.
Another issue concerns function prototype declarators
whose parameters have variable length array types. Since
- 12 -
1/22/93 Arrays of Variable Length X3J11.1/93-007
the dimension size specifiers of variable length array types
in prototype declarators which are not definitions are
resolved, two passes are required over the parameter type
list in order to diagnose undeclared identifiers.
/* prototype declarator whose parameter type remains incomplete */
/* ERROR - `x' and `y' are never declared */
void f1(double a[x][y]);
Rationale:
By assigning all identifiers in VLA size expressions a
universal type that is compatible with any type, the parsing
may proceed to the matching ] token. A possible solution to
the ``lexical ordering problem'' then involves tokenizing,
syntactically analyzing, and marking where the variably
qualified expressions are found within dimension specifiers,
until the ) that terminates the prototype is found. A
second scan of the these variably qualified expressions
associates identifiers with universal types to visible
declarations thereby completing the VLA types. If during
the second scan it is determined that an identifier used in
a VLA size expression is still not visible, a diagnostic
message is produced.
Another issue concerns prototype declarators that contain
parameters with variable length array types that are never
completed. A previous version of this document allowed this
behavior. The motivation was to not force the implementa-
tion to make two passes over the prototype just to issue
diagnostics. A vote that was taken at NCEG meeting #5 in
Norwood, MA, asked the following question:
Q: Which notation is preferred to denote a VLA parameter
(in a prototype)?
Arbitrary [x] (where x can include undeclared names) : 0
[*] : 11
Undecided : 3
Since the [*] syntax seems to be the most widely accepted
this proposal has been changed to reflect this sentiment.
Also, the presence of these diagnostics will help uncover
more programmer errors.
6.5.6 (3.5.6) Type definitions
Constraints
Typedef declarations which specify a variably qualified
type shall have block scope. The array size specified by
- 13 -
1/22/93 Arrays of Variable Length X3J11.1/93-007
the variable length array type shall be evaluated at the
time the type definition is declared and not at the time it
is used as a type specifier in an actual declarator.
Example 16
main() {
extern void func();
func(20);
}
void func(int n) {
typedef int A[n]; /* OK, because declared in block scope */
A a;
A *p;
p = &a;
}
Example 17
int n;
typedef int A[n]; /* wrong, because declared at file scope */
Example 18
void func(int n) {
typedef int A[n]; /* `A' is `n' ints with `n' evaluated now */
n += 1;
{
A a; /* `a' is `n' ints - `n' without += 1 */
int b[n]; /* `a' and `b' are different sizes */
for (i = 1; i < n; i++)
a[i-1] = b[i];
}
}
ISSUE
Overview:
The question arises whether the non-constant expression
which engenders the variable length array type should be
evaluated at the time the type definition itself was
declared or each time the type definition is invoked for
some object declaration.
Rationale:
If the evaluation were to take place each time the
typedef name is used, then a single type definition could
yield variable length array types involving many different
dimension sizes. This possibility seemed to violate the
- 14 -
1/22/93 Arrays of Variable Length X3J11.1/93-007
spirit of type definitions and Cray Research decided to
force evaluation of the expression at the time the type
definition itself is declared.
6.5.7 (3.5.7) Initialization
Constraints
The type of the entity to be initialized shall be an
object type or an array of unknown size, but not a variable
length array type.
Example 19
int n;
main() {
int a[n] = {1, 2}; /* error */
int (*p)[n] = &a; /* ok - pointer is scalar of fixed size */
}
6.6 (3.6) Statements
A full expression is an expression that is not part of
another expression. Each of the following is a full expres-
sion: a variably qualified declarator; an initializer; the
expression in an expression statement; the controlling
expression of a selection statement (if or switch); the
controlling expression of a while or do statement; each of
the three (optional) expressions of a for statement; the
(optional) expression in a return statement. The end of a
full expression is a sequence point.
Example 20
{
int n = 3, m= 4;
int a[n++][n++]; /* order of evaluation is undefined */
int b[m++], c[m++]; /* order of evaluation is defined */
}
Rationale:
Since sequence points control the order of evaluation
of expressions with side effects, it seems reasonable to add
a sequence point after every variably qualified declarator.
This specifies the behavior of declarations such as:
int x[n++];
int y[n++];
- 15 -
1/22/93 Arrays of Variable Length X3J11.1/93-007
in that the side effects must be evaluated at the end of the
declarator. However, the behavior of a declaration such as:
int z[n++][n++];
is not specified because there is no guaranteed order of
evaluation until the declarator is complete. This seems
consistent with an expression such as
z[n++][n++]
in which there is no guaranteed order of evaluation either.
6.6.4.2 (3.6.4.2) Switch statement
Constraints
The controlling expression shall not cause a block to
be entered by a jump from outside the block to a statement
that follows a case or default label in the block (or an
enclosed block) that contains the declaration of a variably
qualified object or variably qualified typedef name.
Example 21
int i;
main() {
int n = 10;
switch (n) { /* error - bypasses declaration of a[n] */
int a[n];
case 10:
a[0] = 1;
break;
case 20:
a[0] = 2;
break;
}
switch (i) { /* OK - declaration of b[n] not bypassed */
case 0:
{
int b[n];
b[2] = 4;
}
break;
case 1:
break;
}
}
ISSUE
Overview:
- 16 -
1/22/93 Arrays of Variable Length X3J11.1/93-007
The concern here is that a switch will bypass evalua-
tion of the arbitrary integer expressions associated with a
variably qualified type. In the case of a simple pointer
that is variably qualified this could cause incorrect
pointer arithmetic. In the case of a variable length array
type this is even more serious in that the variably quali-
fied object itself is not even allocated.
Rationale:
Disallowing use of variably qualified objects in this
fashion seems reasonable and a compile time diagnostic is
issued.
6.6.6.1 (3.6.6.1) Goto statements
Constraints
The identifier in a goto statement shall name a label
located somewhere in the enclosing function. A goto state-
ment shall not cause a block to be entered by a jump from
outside the block to a labeled statement in the block (or an
enclosed block) that contains the declaration of a variably
qualified object or variably qualified typedef name.
Example 22
void func(int n) {
int j = 4;
goto lab3; /* error - going INTO scope of variable length array */
{
double a[n];
a[j] = 4.4;
lab3:
a[j] = 3.3;
goto lab4; /* OK - going WITHIN scope of variable length array */
a[j] = 5.5;
lab4:
a[j] = 6.6;
}
goto lab4; /* error - going INTO scope of variable length array */
return;
}
ISSUE
Overview:
The concern here is that a goto will bypass the evalua-
tion of the arbitrary integer expressions associated with a
variably qualified type. In the case of a simple pointer
that is variably qualified this causes wrong pointer arith-
metic. In the case of a variable length array object, the
- 17 -
1/22/93 Arrays of Variable Length X3J11.1/93-007
object itself would not even be allocated.
Rationale:
Disallowing use of variably qualified objects in this
fashion seems reasonable and a compile time diagnostic is
issued.
6.7.1 (3.7.1) Function Definitions
On entry to the function all size expressions of variably
qualified parameters are evaluated.
7.6.2.1 (4.6.2.1) The longjmp function
Description
If a longjmp function invocation causes the termination
of a function or block in which variable length array
objects are still allocated, then the behavior is undefined.
ISSUE
Overview:
The longjmp function that returns control back to the
point of the setjmp invocation might cause memory associated
with a variable length array object to be squandered. Con-
sider the following program:
- 18 -
1/22/93 Arrays of Variable Length X3J11.1/93-007
Example 23
#include <setjmp.h>
void g(int n);
void h(int n);
int n = 6;
void f() {
int x[n]; /* OK - `f' is not terminated */
setjmp (buf);
g(n);
}
void g(int n) {
int a[n]; /* undefined - `a' is still allocated */
h(n);
}
void h(int n) {
int b[n]; /* undefined - `b' is still allocated */
longjmp(buf,2); /* causes undefined behavior */
}
In this program the function h might cause storage to be
lost for the variable length array object a, declared in
function g (whose existence is unknown to h). Additional
storage could be lost for variable length array object b
declared in function h. In this case an implementation
knows that a longjmp is being performed in the presence of a
variable length array object whose storage needs to be
managed accordingly. However, since longjmp is a function,
it can be invoked through a ``pointer to function'' and thus
h would have no knowledge of the longjmp invocation occur-
ring.
Rationale:
The Cray Research implementation ensures that any vari-
able length array type objects are placed on the existing
stack first and heap storage is used only if room cannot be
found on the stack. Thus, unless things get really big, no
space will be wasted because only vacant space on the stack
was used initially.
- 19 -
1/22/93 Arrays of Variable Length X3J11.1/93-007
LANGUAGE SYNTAX
A.1.2.2 Declarations
(6.5.4), (3.5.4) direct-declarator:
identifier
(declarator)
direct-declarator [assignment-expression "opt"]
direct-declarator [* "opt"]
direct-declarator (parameter-type-list)
direct-declarator (identifier-list "opt")
(6.5.5), (3.5.5) direct-abstract-declarator:
(abstract-declarator)
direct-abstract-declarator [assignment-expression "opt"]
direct-abstract-declarator [* "opt"]
direct-abstract-declarator (parameter-type-list "opt")
- 20 -
More information about the Numeric-interest
mailing list