ANSI-C语法 - 数组声明,如[*] et alii

时间:2010-02-22 16:48:18

标签: c arrays grammar declaration

来自-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 []);

谢谢。

3 个答案:

答案 0 :(得分:15)

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

数组声明中的

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

void foo(int a[static 3]) {
  ...
}

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

数组声明的*大小部分仅用于函数原型声明。它表明该数组具有可变长度(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 */

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

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

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

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 */

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

答案 1 :(得分:1)

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

答案 2 :(得分:0)

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

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

我会假设它使得数组的维度明确地未指定。但我只是在猜测。


嗯... gcc接受

#include <stdio.h>

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<s; ++i){
    printf("%d\n",a[i]);
  }
}

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