为何数组声明器中用作数组大小的逗号表达式必须加括号?
我发现int arr2[(777, 100)]是合法的数组声明,而int arr1[777, 100]却不合法。以下是可编译的示例代码:
#include <stdio.h> void f(int i) { printf("side effect %d\n", i); } int main(void) { // int arr1[777, 100]; // 非法,编译报错 int arr2[(777, 100)]; int arr3[(f(777), 100)]; arr2[10, 20] = 30; arr3[f(40), 50] = 60; return 0; }
这段代码可以通过GCC编译,但无法通过MSVC编译。需要注意的是,逗号表达式在非声明器语境中是完全合法的。
标准依据
根据C17草案(6.7.6.2 ¶3及A.2.1)的规定,数组方括号内的大小必须是assignment-expression而非完整的expression,而逗号运算符属于expression的语法层级:
expression:
assignment-expression
expression , assignment-expression
展开assignment-expression最终会到primary-expression层级,其中包含括号包裹的表达式:
primary-expression:
identifier
constant
string-literal
( expression )
generic-selection
这就解释了为什么带括号的逗号表达式(777, 100)是合法的——它属于primary-expression,符合assignment-expression的要求;而直接写777, 100属于完整的expression,违反了数组维度的语法规则。
语言设计考量
标准这样规定并非无的放矢,主要有两方面考量:
- 简化语法解析:考虑带
static修饰的数组声明(如static int arr[static 10]),限制使用assignment-expression可以避免语法歧义,让编译器更高效地解析声明语句。 - 防止用户误写:避免用户将二维数组声明
int arr[m][n]误写成int arr[m, n],后者如果合法会被解析为逗号表达式,导致数组维度不符合预期。
MSVC编译失败的原因
MSVC无法编译这段代码,主要是因为它对C标准中数组维度的语法实现更为严格。虽然C标准允许括号包裹的逗号表达式作为数组维度,但MSVC的编译器前端可能将数组维度的表达式限制为更基础的常量或无副作用的表达式,或者在处理括号内的逗号表达式时存在逻辑差异,没有完全遵循C标准的语法规则。
内容的提问来源于stack exchange,提问作者Lover of Structure

