什么" [*]" (星号修饰语)在C中的意思是什么?

时间:2016-08-04 19:01:18

标签: c function parameters variable-length-array

在尝试实现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]) {

}

然而,我从未见过它,我也不太了解它的目的。

  1. 它的目的是什么,为什么要添加?
  2. int[]的区别是什么?
  3. int *的区别是什么?

2 个答案:

答案 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)。但是在非定义原型声明中不需要此信息,因此可以将其遗漏并替换为*