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

tur*_*1ng 10 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 '[' ']'
Run Code Online (Sandbox Code Playgroud)

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

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

    void foo(int [*]);

    void foo(int []);

谢谢.

AnT*_*AnT 15

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

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

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

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

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

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

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

void foo(int n, int a[n]); /* `a` is VLA because `n` is not a constant */
Run Code Online (Sandbox Code Playgroud)

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

void foo(int, int a[*]); /* `a` is VLA because size is `*` */
Run Code Online (Sandbox Code Playgroud)

请注意,具有1D阵列的示例不是很好.即使你省略*并声明上述函数为

void foo(int, int a[]);
Run Code Online (Sandbox Code Playgroud)

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

void bar(int n, int m[n][n]) { /* 2D VLA */
  ...
}
Run Code Online (Sandbox Code Playgroud)

原型可能如下所示

void bar(int n, int m[n][n]); /* 2D VLA */
Run Code Online (Sandbox Code Playgroud)

或者作为

void bar(int, int m[*][*]); /* 2d VLA */
Run Code Online (Sandbox Code Playgroud)

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