"[*]"(星号修饰符)在C中的含义是什么?

els*_*ooo 71 c parameters function variable-length-array

在尝试实现C11解析器(用于教育目的)时,我发现在C11(p.470)中也在C99(p.412)中(感谢Johannes!),直接声明符定义为:

(6.7.6) direct-declarator:  
    direct-declarator [ type-qualifier-list? * ]
Run Code Online (Sandbox Code Playgroud)

起初,我认为这是语法中的错误(类型列表不应该是可选的).但是,当我在我的参考编译器(clang)中尝试这个时,我得到了一个意外的错误:

int array[*] = { 1, 2, 3 };
// error: star modifier used outside of function prototype
Run Code Online (Sandbox Code Playgroud)

显然,(在clang中)这被称为星形修饰符.

我很快就知道它们只能在函数签名中使用:

void foobar(int array[*])
Run Code Online (Sandbox Code Playgroud)

但是,它们只能用于声明中.尝试在函数定义中使用它也会导致错误:

void foobar(int array[*]) {
    // variable length array must be bound in function definition
}
Run Code Online (Sandbox Code Playgroud)

所以据我所知,预期的行为是[*]在函数声明中使用,然后在函数定义中使用固定数字.

// public header
void foobar(int array[*]);

// private implementation
void foobar(int array[5]) {

}
Run Code Online (Sandbox Code Playgroud)

但是,我从未见过它,我也不太了解它的目的.

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

hac*_*cks 39

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

当使用可变长度二维数组作为函数参数时,可以看到目的.功能

int foo(int n, int m, int a[n][m])  {...}   
Run Code Online (Sandbox Code Playgroud)

可以原型为以下任何一种

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]); 
Run Code Online (Sandbox Code Playgroud)

在二维数组的情况下,当用作函数参数时,不能省略第二维的大小.如果省略函数原型中的第一个变量的名称,则无法指定数组的长度(第二维).的*给出了该阵列的长度将被第二参数来确定的线索.

有什么区别int[]
有什么区别int *

对于1D数组,用于函数定义

int bar(int n, int a[n]} {...}  
Run Code Online (Sandbox Code Playgroud)

以下任何原型都是有效的

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]);   
Run Code Online (Sandbox Code Playgroud)

在这种情况下既不是*n不必要,因为编译器会同时处理int [*]int [n]as int *.因此,对于一维数组,您看不出太多差异.


注意:使用可变长度数组作为函数参数时,参数顺序很重要.bar可以切换前四个原型的参数顺序,但在后两个参数中,第一个参数不能是数组本身.

int bar (int a[n], int n);  //Wrong. Compiler has not yet seen 'n'.
Run Code Online (Sandbox Code Playgroud)

  • 引用标准*本身*并不是*有任何错误*.事实上,这通常是一个好主意.当答案仅包含标准的引用而没有任何解释时,就会出现问题.通常,如果某人能够准确阅读并理解标准的含义,他们就不会在Stack Overflow上询问有关它的问题.所以一个好的答案(对于一个相关的问题)确实需要做到这两点.如果你必须选择其中一个,我必须同意这些人的说法,并说一个解释优于报价. (8认同)
  • 这直接回答了问题,而不仅仅是引用标准. (5认同)
  • 标准引用直接回答了问题,它是权威的,因为它来自标准.标准报价没有错.(想一想,引用来自理由文件,而不是标准.) (5认同)

Joh*_*itb 15

C99的C基本原理文件说

函数原型可以使用具有可变长度数组类型的参数(第6.5.5.2节),使用特殊语法

int minimum(int, int [*][*]);
Run Code Online (Sandbox Code Playgroud)

这与其他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]);
}
Run Code Online (Sandbox Code Playgroud)

至于目的,在建立索引函数定义数组的时候,编译器需要知道下一个索引的许多整数如何让第一个索引(时跳过x[i]跳过i * n整数在f上面).但是在非定义原型声明中不需要这些信息,因此它可以省略并替换为*.

  • 你的函数原型应该是`void f(int, int x[][*])`。当您为第一个参数命名时,就不需要 `*`。此功能的全部意义在于您可以使用不命名参数的老式函数原型。 (2认同)