web-dev-qa-db-ja.com

Cで「[*]」(星の修飾子)とはどういう意味ですか?

(教育目的で)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では)これはstar modifierと呼ばれます。

関数シグネチャでのみ使用できることをすぐに知りました。

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 *との違いは何ですか?
71
elslooo

その目的は何ですか、なぜ追加されたのですか?

目的は、可変長の2次元配列が関数パラメーターとして使用されるときに見られます。関数

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

2次元配列の場合、関数パラメーターとして使用すると、2番目の次元のサイズは省略できません。関数プロトタイプの最初の変数の名前が省略されている場合、配列の長さ(2番目の次元)を指定することはできません。 *は、配列の長さが2番目のパラメーターによって決定される手がかりを提供します。

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

この場合、コンパイラは*int [*]の両方をint [n]として扱うため、int *nも必要ありません。そのため、1次元配列では、大きな違いは見られません。


注:可変長配列を関数パラメーターとして使用する場合、パラメーターの順序が重要です。 barの最初の4つのプロトタイプのパラメーターの順序は切り替えることができますが、後の2つの最初のパラメーターは配列自体であってはなりません。

int bar (int a[n], int n);  //Wrong. Compiler has not yet seen 'n'.
39
haccks

C99のC根拠文書には、

関数プロトタイプは、次のような特別な構文を使用して、可変長配列型(§6.7.5.2)を持つパラメーターを持つことができます

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

これは、パラメーターの名前を指定する必要のない他のCプロトタイプと一致しています。


Int []との違いは何ですか

Int *との違いは何ですか?.

関数プロトタイプのこれらの型は「ポインタ」を意味し、最上位以外の位置にある[*](関数プロトタイプではint[*]はまだint[]に等しいと思います)は実際に有効であり、meansであると思いますアレイ

// 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]は上記のfi * n整数をスキップします)。ただし、この情報は非定義プロトタイプ宣言では必要ないため、省略して*に置き換えることができます。