I just noticed that int arr2[(777, 100)]
is a legal array declarator, while int arr1[777, 100]
is not.
A more verbose example for compiling would be this
#include <stdio.h>
void f(int i) {
printf("side effect %d\n", i);
}
int main(void) {
// int arr1[777, 100]; // illegal, it seems
int arr2[(777, 100)];
int arr3[(f(777), 100)];
arr2[10, 20] = 30;
arr3[f(40), 50] = 60;
return 0;
}
which compiles fine with GCC (but for some reason not with MSVC).
Also note crucially how the above code illustrates how comma expressions are fine in a non-declarator context.
The reason (for why parentheses are needed in array declarators) appears to be that in the C standard the array size in square brackets is an assignment-expression but not an expression (C17 draft, 6.7.6.2 ¶3 and A.2.1); the latter is the syntactic level for comma operators (C17 draft, A.2.1 (6.5.17)):
expression:
assignment-expression
expression
,
assignment-expression
If one expands assignment-expression, one ultimately gets to the level of primary-expression (C17 draft, A.2.1 (6.5.1)):
primary-expression:
identifier
constant
string-literal
(
expression)
generic-selection
If the standard says so, that's the way it is, but: Is there a syntactic necessity? Perhaps there is a reason based in language design considerations. The C standard lists the following 4 forms of array declarators (C17 draft, 6.7.6.2 ¶3):
D [
type-qualifier-listopt assignment-expressionopt]
D [
type-qualifier-listopt assignment-expression]
D [
type-qualifier-liststatic
assignment-expression]
D [
type-qualifier-listopt]
- One potential reason I can see is to keep this syntax simple, with the 3rd line (with
static
) in mind. - Another potential reason might be to prevent people from writing
int arr[m, n]
when they really meanint arr[m][n]
.
Incidentally, if anyone has comments about why this doesn't compile with MSVC, that would also be appreciated.
`␣␣`
(␣
: space) which I'm using, please let me know, or feel free to edit my post directly. – Damperint arr2[(777, 100)];
? It's equivalent toint arr2[100];
– Sensitometerint arr3[(f(777), 100)];
is equivalent tof(777); int arr3[100];
. – Sensitometer(
after thefor
(and perhaps after thewhile
too) isn't really necessary. – Groutfor
- andwhile
-loops (C17 draft, 6.8.5 ¶1). – Damper(
after thefor
(and perhaps after thewhile
too) isn't really necessary. – Groutsizeof ( type-name )
(as well as in_Alignof ( type-name )
) the()
are technically required (i.e. strictly speaking non-redundant)? – Groutsizeof int * + 0
should be parsed as(sizeof int) * (+ 0)
, but actually I think the example works, because*
within a type designator isn't actually covered by the standard operator precedence rules. Note that I didn't check whether the grammar given in the standard would literally be ambiguous ifsizeof typename
were allowed – as you will know, the operator precedence rules are only implicit in the standard, because they follow from its grammar.) – Damper