ANSI-C语法-数组声明,如[*]等
来自的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
(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&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 */