web-dev-qa-db-fra.com

Que signifie "[*]" (modificateur étoile) en C?

En essayant d'implémenter un analyseur C11 (à des fins éducatives), j'ai trouvé que dans C11 (p. 470) mais aussi dans C99 (p. 412) (merci Johannes! ), le déclarateur direct est défini comme:

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

Au début, je pensais que c'était une erreur de grammaire (la liste des types ne devrait pas être facultative). Cependant, lorsque j'ai essayé cela dans mon compilateur de référence (clang), j'ai eu une erreur plutôt inattendue:

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

Donc apparemment, (en clang), cela s'appelle le modificateur étoile .

J'ai rapidement appris qu'ils ne peuvent être utilisés que dans les signatures de fonction:

void foobar(int array[*])

Cependant, ils ne peuvent être utilisés que dans la déclaration. Essayer de l'utiliser dans une définition de fonction entraîne également une erreur:

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

Donc, pour autant que je sache, le comportement prévu est d'utiliser [*] dans la déclaration de fonction, puis utilisez un nombre fixe dans la définition de la fonction.

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

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

}

Cependant, je ne l'ai jamais vu et je ne comprends pas très bien son but non plus.

  1. Quel est son but, pourquoi a-t-il été ajouté?
  2. Quelle est la différence avec int[]?
  3. Quelle est la différence avec int *?
71
elslooo

Quel est son but, pourquoi a-t-il été ajouté?

Le but est vu lorsqu'un tableau à deux dimensions de longueur variable est utilisé comme paramètre de fonction. La fonction

int foo(int n, int m, int a[n][m])  {...}   

peut être prototypé comme l'un des suivants

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

Dans le cas d'un tableau à deux dimensions, lorsqu'il est utilisé comme paramètre de fonction, la taille de la deuxième dimension ne peut pas être omise. Si le nom des premières variables dans le prototype de fonction est omis, il ne serait pas possible de spécifier la longueur (deuxième dimension) du tableau. Le * donne l'indice que la longueur du tableau sera déterminée par le deuxième paramètre.

Quelle est la différence avec int[]?
Quelle est la différence avec int *?

Dans le cas d'un tableau 1D, pour la définition de la fonction

int bar(int n, int a[n]} {...}  

l'un des prototypes suivants est valide

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

Dans ce cas, ni * ni n est nécessaire car le compilateur traitera les deux int [*] et int [n] comme int *. Donc, avec un tableau unidimensionnel, vous ne voyez pas beaucoup de différence.


REMARQUE: lorsque vous utilisez un tableau de longueur variable comme paramètre de fonction, l'ordre des paramètres est important. L'ordre des paramètres pour les quatre premiers prototypes de bar peut être changé, mais dans les deux derniers, le premier paramètre ne doit pas être le tableau lui-même.

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

Le document de justification C pour C99 dit

Un prototype de fonction peut avoir des paramètres qui ont des types de tableau de longueur variable (§6.7.5.2) en utilisant une syntaxe spéciale comme dans

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

Ceci est cohérent avec d'autres prototypes C où le nom du paramètre n'a pas besoin d'être spécifié.


Quelle est la différence avec int []

Quelle est la différence avec int *.

Je pense que c'est simplement que ces types dans un prototype de fonction signifient "pointeur", tandis qu'un [*] en position non supérieure (int[*] est toujours égal à int[] Je pense, dans un prototype de fonction) est en fait valide et signifie tableau

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

En ce qui concerne le but, lors de l'indexation du tableau dans la définition de fonction, le compilateur a besoin de savoir combien d'entiers du prochain index à ignorer lors de la fourniture du premier index (x[i] saute i * n entiers dans f ci-dessus). Mais ces informations ne sont pas nécessaires dans la déclaration de prototype non définissante, elles peuvent donc être omises et remplacées par *.

15