The C[] language, being a vector subset of the mpC language, is extended to provide some restricted facilities allowing to specify array types of dynamic size (and step) and operate on dynamic arrays and vectors.
Firstly, C[] allows to use in a definition of an automatic data object not only a constant expres sion to specify array size or step, but an expression evaluated in run time. In this case, the corre sponding attributes are evaluated on each normal entry into the block in which the definition appears and remain constant during the execution of the block. For example, in the following fragment
int n, m;
Input1(&n, &m); /* Initialize n, m */
{
double a[n], b[n], c[n:m];
Input2(a, b, n); /*Initialize arrays a and b*/
c[]=a[]+b[];
...
}
the automatic variables a and b are of the dynamic type "array of n doubles with step 1", and
the variable c has the dynamic type "array of n doubles with step m". The user is responsible
for correctness of dynamically-defined attributes, since two arrays of members that have the same
type are treated as having the same type if their sizes and steps are defined in run time. Therefore,
for example, if the sizes of a, b, and c were specified with different expressions, the expression
c[]=a[]+b[] would be considered allowable but could cause undefined behavior if the sizes
were different.
Secondly, C[] extends potentialities of type names used in C in cast expressions and in sizeof operators. Namely, C[] allows to use in type names not only a constant expression to specify array size or step, but an expression evaluated in run time. For example, if n and m are integer variables, then type names int(*)[n] and double(*const[n*m])(unsigned int, ...) are allowable in C[]. Like in C, in C[] such dynamic type names can be used in cast expressions and in sizeof operators. So, if the variable p is of the type "pointer to void", then the expression *(int(*)[n])p has the type "array of n ints" and the expression (*(int(*)[n])p)[] is a blocked lvalue. The following fragment demonstrates the usage of dynamic type names:
double *a, *b, *:2 c; int n; Input1(&n); /*Initialize n*/ a=malloc(sizeof(double[n])); b=malloc(sizeof(double[n])); c=malloc(sizeof(double[n:2])); Input2(a, b, n); /*Initialize arrays a and b*/ c[]=a[]+(*(double(*)[n])b)[];Here, the expressions a[] and c[] show that the operator [] may be applied not only to expres sions having the type "array of type with step", but also to expressions having the type "pointer to type with step". The result is treated as a blocked array of type of undefined size with step. The size attribute of such an array is determined from context (here, borrowed from other operand of the binary operator + or = correspondingly).
Thirdly, C[] extends potentialities of typedef declarations, allowing one to use not only con stant expressions to specify array sizes or steps, but also expressions evaluated in run time. A dynamic typedef declaration introduces a synonym for a dynamic type whose attributes are evaluated on each normal entry into the block in which the declaration appears and remain con stant during the execution of the block. The typedef name introduced by the dynamic typedef declaration can be used in cast expressions, sizeof operators, dynamic typedef declarations or as a type specifier in declarations. For example, the above fragment can be rewritten as follows
double *a, *b, *:2 c;
int n;
Input1(&n);
{
typedef double T[n], T_2[n:2];
T ta, tb;
T_2 tc;
a=ta;
b=tb;
c=tc;
Input2(a, b, n);
tc[]=ta[]+tb[];
}