在尝试实现C11解析器(用于教育目的)时,我发现在C11 (p. 470)但在C99 (p. 412)中(感谢Johannes!),直接声明器是定义为:
(6.7.6) direct-declarator:
direct-declarator [ type-qualifier-list? * ]
起初,我认为这是语法错误(类型列表不应该是可选的)。但是,当我在我的参考编译器(clang)中尝试这个时,我得到了一个意想不到的错误:
int array[*] = { 1, 2, 3 };
// error: star modifier used outside of function prototype
显然,(在clang中)这被称为星形修饰符。
我很快就知道它们只能用于功能签名:
void foobar(int array[*])
但是,它们只能在声明中使用。尝试在函数定义中使用它也会导致错误:
void foobar(int array[*]) {
// variable length array must be bound in function definition
}
据我所知,预期的行为是在函数声明中使用[*]
,然后在函数定义中使用固定数字。
// public header
void foobar(int array[*]);
// private implementation
void foobar(int array[5]) {
}
然而,我从未见过它,我也不太了解它的目的。
int[]
的区别是什么?int *
的区别是什么?答案 0 :(得分:39)
它的目的是什么,它为什么被添加?
当使用可变长度二维数组作为函数参数时,可以看到目的。功能
int foo(int n, int m, int a[n][m]) {...}
可以原型为以下任何一种
int foo(int , int, int [][*]);
int foo(int , int, int a[*][*]);
int foo(int , int, int (*a)[*]);
int foo(int n, int, int a[n][*]);
int foo(int , int m, int a[*][m]);
int foo(int , int m, int (*a)[m]);
int foo(int n, int m, int a[n][m]);
在二维数组的情况下,当用作函数参数时,不能省略第二维的大小。如果省略函数原型中的第一个变量的名称,那么就不可能指定数组的长度(第二维)。 *
给出了一个线索,即数组的长度将由第二个参数决定。
与
int[]
的区别是什么? 与int *
的区别是什么?
对于1D数组,对于函数定义
int bar(int n, int a[n]} {...}
以下任何原型都有效
int bar (int , int *);
int bar (int , int [*]);
Int bar (int , int []);
int bar (int n, int a[]);
int bar (int n, int a[n]);
int bar (int n, int [n]);
在这种情况下,*
和n
都不是必需的,因为编译器会将int [*]
和int [n]
都视为int *
。因此,使用一维数组,您可以看到很多不同。
注意:使用可变长度数组作为函数参数时,参数顺序很重要。可以切换bar
的前四个原型的参数顺序,但在后两个参数中,第一个参数不能是数组本身。
int bar (int a[n], int n); //Wrong. Compiler has not yet seen 'n'.
答案 1 :(得分:15)
C99的C基本原理说明
函数原型可以使用具有可变长度数组类型的参数(第6.5.5.2节),使用特殊语法,如
int minimum(int, int [*][*]);
这与其他C原型一致,其中不需要指定参数的名称。
与int []
有什么区别与int *有什么区别。
我认为只是函数原型中的那些类型意味着“指针”,而非顶部位置的[*]
(int[*]
仍然等于int[]
我认为,函数原型)实际上是有效的,意味着数组
// not recommended though: it is now unclear what the parameters
// mean to human callers!
void f(int, int [][*]);
void f(int n, int x[][n]) {
x[1][0] = 1;
}
int main() {
int a[2][1];
f(1, a);
printf("%d\n", a[1][0]);
}
至于目的,当在函数定义中索引数组时,编译器需要知道在给出第一个索引(x[i]
跳过i * n
整数时要跳过的下一个索引的整数数量上面f
)。但是在非定义原型声明中不需要此信息,因此可以将其遗漏并替换为*
。