ANSI-C语法 – 数组声明,如 et alii

来自-link-的ANSI C语法给出了以下数组声明规则:

(1) | direct_declarator '[' type_qualifier_list assignment_expression ']' (2) | direct_declarator '[' type_qualifier_list ']' (3) | direct_declarator '[' assignment_expression ']' (4) | direct_declarator '[' STATIC type_qualifier_list assignment_expression ']' (5) | direct_declarator '[' type_qualifier_list STATIC assignment_expression ']' (6) | direct_declarator '[' type_qualifier_list '*' ']' (7) | direct_declarator '[' '*' ']' (8) | direct_declarator '[' ']' 

现在我对这些问题有一些疑问:

  • 除了(3)只能在C99中使用(1) – (6)吗?
  • 什么是(4)和(5)? 关键字“静态”让我困惑。
  • 在哪里使用(6)?
  • 以下两个函数原型之间的区别是什么:

    void foo(int [*]);

    void foo(int []);

谢谢。

在C89 / 90中,不能在数组声明的大小部分中使用类型限定符或static 。 这些function特定于C99。

数组声明中的static告诉编译器你保证指定数量的元素将始终存在于作为实际参数传递的数组中。 这可能有助于编译器生成更高效的代码。 如果您在实际代码中违反了您的承诺(即传递较小的数组),则行为未定义。 例如,

 void foo(int a[static 3]) { ... } int main() { int a[4], b[2]; foo(a); /* OK */ foo(b); /* Undefined behavior */ } 

数组声明的* in size部分仅用于函数原型声明。 它表明该数组具有可变长度(VLA)。 例如,在函数定义中,您可以使用具有特定运行时大小的VLA

 void foo(int n, int a[n]) /* `a` is VLA because `n` is not a constant */ { ... } 

声明原型时,您也可以这样做

 void foo(int n, int a[n]); /* `a` is VLA because `n` is not a constant */ 

但是如果你没有指定参数名称(在原型中是正常的),你当然不能使用n作为数组大小。 但是,如果您仍然必须告诉编译器该arrays将成为VLA,您可以使用*来实现此目的

 void foo(int, int a[*]); /* `a` is VLA because size is `*` */ 

请注意,具有1Darrays的示例不是很好。 即使省略*并将上述函数声明为

 void foo(int, int a[]); 

然后代码仍然可以正常工作,因为在函数参数声明中,数组类型无论如何都被隐式替换为指针类型。 但是一旦你开始使用多维数组,正确使用*变得很重要。 例如,如果函数定义为

 void bar(int n, int m[n][n]) { /* 2D VLA */ ... } 

原型可能如下所示

 void bar(int n, int m[n][n]); /* 2D VLA */ 

或者作为

 void bar(int, int m[*][*]); /* 2d VLA */ 

在后一种情况下,第一个*可以省略(因为数组到指针替换),但不是第二个*

我希望你不是试图从yacc规范学习C语法!? 您发布的链接似乎基于ISO C99草案 。 相关部分是6.7.5.2。 措辞是神秘的(但也许不如yacc语法!)

我的K&R2nd(涵盖并包含ANSI标准)似乎没有在文本或标准本身中提及[*] 。 我也不能在标准中使用官方语法接受该语法。

它可能与K&R c有关(虽然我似乎不记得它),可能是一个共同的延伸,或者是一个最终没有达到标准的提案。

认为它明确地未指定数组的维度。 但我只是在猜测。


嗯…… gcc接受了

 #include  void f(int s, int a[*]); int main(void){ int a[2] = {0}; f(2,a); return 0; } void f(int s, int a[]){ int i; for (i=0; i 

在ansi,c89和c99模式; 即使使用-Wall不会发出警告。 请注意,它不喜欢函数定义中的[*]语法。 添加-pedantic让它抱怨c89和ansi模式中的[*]语法,但它继续在c99模式下接受。