I'm looking at the C2Y draft n3467 and trying to wrap my heads around something involving functions taking VLAs.
It seems there's an undefined behavior that's not mentioned by the standard. That is:
Here's my code demonstrating this. Although the resulting behavior ultimately made sense, I don't understand (Q:) why the standard never declared this undefined/unspecified/implemenation-defined behavior. The particular sections, 6.7.7.3. Array and 6.7.7.4. Function Declarators in 6.7. Declaration section, and 6.9.2. Function Definitions in External Declarations section, the might-be UB is mentioned no where in these places.
#include <stdio.h>
#include <stdlib.h>
extern int d, e;
int g(int z[3][*][*]);
int main()
{
int z[3][d][e];
for(int i=0; i<3; i++)
for(int j=0; j<d; j++)
for(int k=0; k<e; k++)
z[i][j][k] = i*d*e+j*e+k;
int x = g(z);
printf("%zd, %d.\n", sizeof(float[x]), x);
return 0;
}
extern int u, v;
int g(int z[3][v][u])
{
return z[0][2][2];
}
The external variables are defined like this:
int u = 3, v = 5;
int d = 7, e = 7;
Output:
32, 8.
Section 6.5.3.3 paragraph 6 describes how arguments are converted in a function call:
The arguments are implicitly converted, as if by assignment, to the types of the corresponding parameters, taking the type of each parameter to be the unqualified version of its declared type...
After array-to-pointer conversion and the automatic adjustment of declared function argument types, g(z)
calls a function with parameter type int (*)[v][u]
, passing an argument of type int (*)[d][e]
. The argument type is converted to the parameter type as if by assignment.
So is it okay to perform that assignment?
Well, the constraints on assignment are described in section 6.5.17.2 paragraph 1. The relevant section is as follows:
the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left operand has all the qualifiers of the type pointed to by the right operand;
So these pointers need to point to qualified or unqualified versions of compatible types. Do they?
Well, section 6.7.7.3 paragraph 6 says the following:
For two array types to be compatible, both shall have compatible element types, and if both size specifiers are present, and are integer constant expressions, then both size specifiers shall have the same constant value. If the two array types are used in a context which requires them to be compatible, the behavior is undefined if the two size specifiers evaluate to unequal values.
The array types int [v][u]
and int [d][e]
are being used in a context that requires them to be compatible, but the size specifiers don't match. The behavior is undefined.