GNT sans publicité, site mobile, fonctionnalitées exclusives...

Questions sur les déclarateurs de fonctions

Le
Taurre
Bonjour à tous,

Je m'excuse d'avance pour le titre un peu flou, mais j'avoue ne pas
avoir trouvé mieux.
Je viens vers vous car j'ai deux questions en rapport avec les
"déclarateurs" de fonctions, plus précisémment au sujet des paramèt=
res
de type tableaux:

- j'ai lu qu'il était possible d'indiquer qu'une fonction recevait un
tableau de longueur variable comme ceci:

void fonction(int tab[*]);

Cependant, je ne comprend pas l'intérêt de cette écriture qui est
limitée aux prototypes de fonctions (6.7.5.3 § 12 p 119). En effet,
dans le cas où je passes un tableau de longueur variable en argument
d'une fonction, ce dernier est implicitement converti en un pointeur
sur son premier élément (6.3.2.1 § 3 p 46). J'aurais donc très bien=
pu
me contenter de spécifier tab comme de type "pointeur sur int". Dès
lors, où est l'intérêt de l'écriture ci-dessus?

- j'ai également vu qu'il était possible d'utiliser le mot-clé static
juste avant la taille d'un paramètre de type tableau, par exemple
comme ceci:

void fonction(int tab[static 10]);

À ce sujet, la Norme nous dit (6.7.5.3 § 7 p 119):

> If the keyword static also appears within the [ and ] of the
> array type derivation, then for each call to the function, the value of t=
he corresponding
> actual argument shall provide access to the first element of an array wit=
h at least as many
> elements as specified by the size expression.

Je comprends cette phrase comme une obligation pour le tableau fourni
en argument d'avoir une taille minimale. Cependant, je constate que
violer cette interdiction n'entraîne aucune erreur/avertissement du
côté de GCC (4.4.5). Dès lors, de nouveau, quel est l'intérêt de =
cette
écriture si elle est purement indicative puisque dans ce cas, indiquer
la taille sans le mot-clé static suffit?

Merci d'avance pour vos réponses.
Lire les 12 réponses

Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses Page 1 / 3
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Antoine Leca
Le #24087461
Taurre écrivit :
- j'ai lu qu'il était possible d'indiquer qu'une fonction recevait un
tableau de longueur variable comme ceci:

void fonction(int tab[*]);

Cependant, je ne comprend pas l'intérêt de cette écriture qui est
limitée aux prototypes de fonctions (6.7.5.3 § 12 p 119).



Permettre de savoir qu'il s'agit d'un tableau (« à taille variable »),
ce qui permet à la fonction de le manipuler comme un tableau (par
exemple en utilisant sizeof dessus), plutôt que comme un pointeur vers
le premier élément comme c'est habituel en C.

En effet, dans le cas où je passes un tableau de longueur variable en
argument d'une fonction, ce dernier est implicitement converti en un
pointeur sur son premier élément (6.3.2.1 § 3 p 46).



"Except when it is the operand of the sizeof operator, or the
unary & operator"

Dans le cas d'un paramètre tableau « normal » (type_t toto[]), de par
6.7.5.3 alinéa 7, l'objet (ici toto) est vu dans le corps de la fonction
comme un pointeur ; en dehors des cas ci-dessus il n'y a donc pas de
différences au final ; mais si tu écris sizeof(toto) tu va récupérer la
taille d'un pointeur, ce qui n'a pas grand intérêt ; par contre
sizeof(tab) va te donner la taille du tableau passé comme argument à la
fonction.


void fonction(int tab[static 10]);

Je comprends cette phrase comme une obligation pour le tableau fourni
en argument d'avoir une taille minimale. Cependant, je constate que
violer cette interdiction n'entraîne aucune erreur/avertissement du
côté de GCC (4.4.5).



Remarque tout d'abord que http://gcc.gnu.org/gcc-4.4/c99status.html
spécifie que le support pour les tableaux à taille dynamique est
"broken" (cassé), les résultats ne sont donc pas très probants.

Par ailleurs, on est dans le cas typique de « il ne faut pas faire
cela ! » Le texte spécifie (par l'écriture "shall") que l'obligation de
s'assurer de la conformité relève de la responsabilité du programmeur,
et que s'il ne le fait pas on tombe dans le royaume insondable du
comportement indéfini...
Même si le cas que tu as testé paraît évident (et de fait un bon
compilateur /devrait/ émettre un diagnostic), si tu te places dans le
cas suivant, la détection devient plus compliquée :

------8<------
void f(int tab[static 20]);

void g(int inter[*])
{
f(inter);
}

------8<------

void g(int inter[*]);

void h(void)
{
int tableau[12];
g(tableau);
}
------8<------


Le fond de toutes ces syntaxes apparemment bizarres si tu apprends le C
en 2011 après avoir peut-être rencontré un autre langage, est à
rechercher dans l'histoire et la nécessité de compatibilité ascendante.
La formulation sans static ni * était la seule permise (et reconnue)
avant 1998 ; pour implémenter ces extensions, il a fallu inventer des
nouvelles constructions ; parfois baroques, c'est vrai.


Antoine
espie
Le #24087861
De toutes facons, personne n'utilise ces nouvelles syntaxes.

Entre autres, parce que le support est plus ou moins casse, et donc
que ca ferait du code "moins portable", ce qui est quand meme toujours
un gros interet du C.

Aussi, parce que de toutes facons, c'est juste du sucre syntaxique.
Passer du tableau dynamique a base de f(int t[*]), ca sera de toutes
facons exactement aussi efficace que le classique f(int t[], size_t n)
qui lui a l'avantage de fonctionner depuis C89.

Et si f(static int t[10]) ne "fonctionne" pas, c'est pas si grave...
ou plus exactement, je soupconne fort que, le jour ou il fonctionnera, le
compilo aura suffisamment de jugeotte pour faire les verifications
correspondantes dans des cas qui ne sont pas annotes...
Taurre
Le #24088051
Tout d'abord merci pour ces réponses :)

Le fond de toutes ces syntaxes apparemment bizarres si tu apprends le C
en 2011 après avoir peut-être rencontré un autre langage, est à
rechercher dans l'histoire et la nécessité de compatibilité ascenda nte.
La formulation sans static ni * était la seule permise (et reconnue)
avant 1998 ; pour implémenter ces extensions, il a fallu inventer des
nouvelles constructions ; parfois baroques, c'est vrai.



Je comprends tout à fait le besoin d'inventer de nouvelles syntaxes
afin de conserver celles existantes, c'est d'ailleurs un point que
j'apprécie en C ;)
Maintenant, pour reprendre l'exemple de static, c'est son intérêt que
je ne comprends pas... En effet, si le but est purement indicatif, que
les compilateurs ne sont pas obligés d'émettre un diagnostic et qu'en
plus il est impossible/difficile d'effectuer des vérificaions dans
certains cas, je ne comprends pas pourquoi cela a été inventé... Le
programmeur pourrait tout aussi bien se contenter d'indiquer la taille
nécessaire sans ce mot-clé, cela reviendra au même.

> - j'ai lu qu'il était possible d'indiquer qu'une fonction recevait un
> tableau de longueur variable comme ceci:

> void fonction(int tab[*]);

> Cependant, je ne comprend pas l'intérêt de cette écriture qui est
> limitée aux prototypes de fonctions (6.7.5.3 § 12 p 119).

Permettre de savoir qu'il s'agit d'un tableau (« à taille variable »),
ce qui permet à la fonction de le manipuler comme un tableau (par
exemple en utilisant sizeof dessus), plutôt que comme un pointeur vers
le premier élément comme c'est habituel en C.



Apparemment non, car au point 6.7.5.3 § 12, la norme précise que cela
ne peut être utilisé que dans les prototypes et non dans les
définitions de fonctions:

If the function declarator is not part of a definition of that function, parameters may have
incomplete type and may use the [*] notation in their sequences of declar ator specifiers
to specify variable length array types.



D'ailleurs, si je compile ce code d'exemple avec GCC et Clang,
j'obtiens:

#include #include

void
affiche_taille(int tab[*])
{
printf("%zun", sizeof tab);
}


int
main(void)
{
unsigned n;

if (scanf("%u", &n) == 1) {
int tab[n];
affiche_taille(tab);
}

return EXIT_SUCCESS;
}

GCC:
main.c:7: error: ‘[*]’ not allowed in other than function prototype s cope



Clang:
main.c:6:20: error: variable length array must be bound in function defin ition
affiche_taille(int tab[*])



Dès lors, de nouveau, je ne comprends pas l'utilité de cette syntaxe.

Aussi, parce que de toutes facons, c'est juste du sucre syntaxique.
Passer du tableau dynamique a base de f(int t[*]), ca sera de toutes
facons exactement aussi efficace que le classique f(int t[], size_t n)
qui lui a l'avantage de fonctionner depuis C89.

Et si f(static int t[10]) ne "fonctionne" pas, c'est pas si grave...
ou plus exactement, je soupconne fort que, le jour ou il fonctionnera, le
compilo aura suffisamment de jugeotte pour faire les verifications
correspondantes dans des cas qui ne sont pas annotes...



Je suis entièrement d'accord, ce ne sont visiblement pas des éléments
importants et on peut franchement sans passer. Cependant, c'est
surtout par curiosité que je pose la question, j'aimerais juste savoir
à quoi serve concrètement ces syntaxes.
espie
Le #24088131
In article Taurre

Je suis entièrement d'accord, ce ne sont visiblement pas des éléments
importants et on peut franchement sans passer. Cependant, c'est
surtout par curiosité que je pose la question, j'aimerais juste savoir
à quoi serve concrètement ces syntaxes.



Ben, a rien !
Taurre
Le #24088121
On 19 déc, 12:22, (Marc Espie) wrote:
In article
Taurre  
>Je suis entièrement d'accord, ce ne sont visiblement pas des éléme nts
>importants et on peut franchement sans passer. Cependant, c'est
>surtout par curiosité que je pose la question, j'aimerais juste savoir
>à quoi serve concrètement ces syntaxes.

Ben, a rien !



J'ai quand même un peu de mal à avaler qu'un comité de normalisation
composé (normalement) de professionnels et de gens compétents, ajoute
de nouvelle syntaxes au langage juste pour faire joli. Il doit quand
même bien y avoir un petite idée ou une petit raison derrière ces
ajouts non (autre que de faire joli)?
Publicité
Suivre les réponses
Poster une réponse
Anonyme