C中的“”(星号修饰符)是什么意思?

在试图实现一个C11parsing器(为了教育目的)时,我发现在C11(470页),但也在C99(412页) (感谢Johannes!), 直接声明符被定义为:

(6.7.6) direct-declarator: direct-declarator [ type-qualifier-list? * ] 

起初,我认为这是语法错误(types列表不应该是可选的)。 但是,当我在我的参考编译器(铿锵声)中尝试了这一点,我得到了一个意想不到的错误:

 int array[*] = { 1, 2, 3 }; // error: star modifier used outside of function prototype 

很明显,(在叮当中)这叫做星形修饰符

我很快就了解到,他们只能用于function签名:

 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 *什么区别?

它的目的是什么,为什么添加?

当可变长度的二维数组用作函数参数时,可以看到目的。 function

 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]); 

在二维数组的情况下,当用作函数参数时,二维的大小不能省略。 如果省略函数原型中第一个variables的名称,那么就不可能指定数组的长度(第二维)。 *给出的线索,arrays的长度将由第二个参数确定。

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'. 

C99的C原理文件说

一个函数原型可以使用一个特殊的语法来使用具有可变长度数组types的参数(§6.7.5.2)

 int minimum(int, int [*][*]); 

这与其他C原型是一致的,其中参数的名称不需要指定。


与int []有什么区别

与int *有什么不同?

我认为这仅仅是函数原型中的那些types意味着“指针”,而非顶级位置中的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]跳过上面f i * n整数x[i]时下一个索引要跳过多less个整数。 但是这个信息在非定义的原型声明中是不需要的,因此它可以被忽略并且被*代替。