Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: implemented Keaton's changes; other edits

...

Section 6.7.6.1, paragraph 1, summarizes the array index syntax extensions:

In addition to optional type qualifiers and the keyword static, the ... the [ and ] may delimit
an delimit an expression or *. If they delimit an expression (which specifies the size of an array), the
the  expression shall have an integer type. If the expression is a constant expression, it shall
have  have a value greater than zero. The element type shall not be an incomplete or function
type. The optional type qualifiers and the keyword static shall appear only in a
declaration of a function parameter with an array type, and then only in the outermost
array type derivation.function type.

Consequently, an array declaration that serves as a function argument may have an index that is a variable or an expression. This does not indicate that the argument indicates a VLA, as the array argument is demoted to a pointer. But it can be used by developers to indicate the expected bounds of the array. This information may be used by compilers, or it may be ignored. But such declarations are useful to other developers as they serve to document relationships between array sizes and other relevant variables. Furthermore, the information can also be used by static analysis tools.

...

Standard Examples

Section 6.7.6.3 of C11 the C Standard has several examples of conformant array parameters. Example 4 illustrates a variably modified parameter:

Code Block
void addscalar(int n, int m,                double a[n][n*m+300], double x);

int main(void) {
  double b[4][308];
  addscalar(4, 2, b, 2.17);
  return 0;
}

void addscalar(int n, int m,                double a[n][n*m+300], double x) {
  for (int i = 0; i < n; i++)
  for (int j = 0, k = n*m+300; j < k; j++)
    // a is a pointer to a VLA with n*m+300 elements
    a[i][j] += x;
}

...

Code Block
double maximum(int n, int m, double a[n][m]);
double maximum(int n, int m, double a[*][*]);
double maximum(int n, int m, double a[ ][*]);
double maximum(int n, int m, double a[ ][m]);

These prototype declarators are also compatible:

Code Block
void f(double (* restrict) a)[5]);
void f(double a[restrict][5]);
void f(double a[restrict 3][5]);
void f(double a[restrict static 3][5]);

C11 concludes with the following note regarding example 5:

Note that the last declaration also specifies that the argument corresponding to a in any call to f must be a
non-null pointer to the first of at least three arrays of 5 doubles, which the others do not.

 

Noncompliant Code Example

...

This compliant solution declares the size_t variable n before using it in the subsequent array declaration. Consequently this code complies with the standard and successfully documents the relationship between the array parameter and the size parameter.

Code Block
bgColor#ccccff
langc
void my_memset(size_t n, char p[n], char v) {
  memset( p, v, n);
}

Exceptions

API05-EX0: The extended array syntax is not supported by Microsoft Visual C/C++. MSVC.  Consequently C libraries programs that must support Windows need not use conformant array parameters.

One option for cross-platform for portable code that must support MSVC would be is to use macros:

Code Block
bgColor#ccccff
langc
#include <stddef.h>
  
#if defined (_MSC_VER)
  #define N(x)
#else
  #define N(x)  (x)
#endif
  
int f(size_t n, int a[N(n)]);

...