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

ANSI-C语法-数组声明,如[*]等,c,arrays,grammar,declaration,C,Arrays,Grammar,Declaration,来自的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_q

来自的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 '[' ']'
现在我有一些关于这些的问题:

  • 我可以只在C99中使用(1)-(6)而不是(3)吗
  • (4)和(5)是干什么用的?“静态”这个关键词让我很困惑
  • 在哪里使用(6)
  • 以下两个功能原型之间有什么区别:

    void foo(int[*])

    voidfoo(int[])

谢谢。

我的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]);
  }
}
#包括
无效f(整数s,整数a[*]);
内部主(空){
int a[2]={0};
f(2,a);
返回0;
}
空f(整数s,整数a[]){
int i;

对于(i=0;i我希望您不是试图从yacc规范中学习C语法!?您发布的链接似乎基于此。相关部分为6.7.5.2。措辞晦涩难懂(但可能不如yacc语法!)

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

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

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
作为数组大小。但是,如果仍然必须告诉编译器数组将是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 */
或作为


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

-Wall不会对C89中被视为GNU扩展的所有语法发出警告。我认为您还需要-pedantic来实现这一点。K&R第二版是针对ANSI C89(现在的ISO C90)编写的标准,因此不包括C99语法。C99添加了可变长度数组和其他与数组相关的语法。关于不喜欢函数定义中的[],标准说[]“是一种大小未指定的可变长度数组类型,只能在具有函数原型作用域的声明中使用”我想这真正重要的地方是当你做
f(int,int,inta[*][*])
或诸如此类的事情时…@dmckee:我只是在我的答案中加了一句:)这里很多人的想法都是一样的“来自-link的ANSIC语法-给我以下数组声明规则”。我建议这些规则是为yacc使用而不是为人类使用的,ISO标准是为人类使用的(并且是yacc的源文档)。我说的是“C语法”,而不仅仅是“C语法”“你可以将C语言学习到一个工作水平,而不需要复杂的语法知识。也许你当时正在编写编译器或静态分析器?哦,对不起,我读得太快了。是的,这是针对静态分析器的。”。
void bar(int, int m[*][*]); /* 2d VLA */