cast de pointeur *, ** différence ?
Le
Nico

salut,
j'ai un petit code qui m'étonne soit une fonction prenant un void*
en paramètre, lors de son appel, si je lui passe un double*, mon
compilateur dit rien ok.
soit une fonction retournant un void *, lorsque j'assigne un double*
avec le retour de cette fonction, mon compilateur ne dit rien
ici donc, pas besoin de caster ni le paramètre (en (void*)), ni le
retour de fonction (en (double*))
maintenant, on prend les même et on recommence, à la différence près
que mon argument n'est plus un void* mais un void**, et mon retour
n'est plus un void* mais aussi un void **. là plus rien ne passe
lors de l'appel de la fonction je suis obligé de caster mon double** en
void**, et lors du retour, je suis obligé de caster en double**,
pourquoi ?
pour un exemple plus parlant, considérez le code suivant :
void *
vect_new(size_t len, size_t size_type)
{
void *v = malloc(len * size_type);
return v;
}
void
vect_free(void *vect)
{
if(vect) free(vect);
}
/*declaration du vecteur
pas besoin de faire un cast (double*)*/
double *vect = vect_new(3,sizeof(double));
/*appel sans probleme a la compilation :
pas besoin de faire (void*)vect*/
vect_free(vect);
et maintenant avec des void** :
void **
mat_new(unsigned int nrow, unsigned int ncol, size_t size_type)
{
int i,j;
void **m = malloc(nrow * size_type);
if(m)
{
for(i=0; i<nrow; i++)
{
m[i] = malloc(ncol * size_type);
if(!m[i])
{
for(j=0; j<=i; j++)
free(m[i]);
free(m);
m = NULL;
}
}
}
return m;
}
void
mat_free(void **m,unsigned int nrow)
{
int i;
if(m)
{
for(i=0; i<nrow; i++)
if(m[i])
free(m[i]);
free(m);
}
}
/*declaration de la matrice*/
double **matrice = (double**)mat_new(4,3,sizeof(double));
/*appel sans probleme a la compilation : */
mat_free((void**)matrice,4);
là si je cast pas l'un et l'autre warning où se situe la
différence avec le 1er exemple ?
merci de m'éclairer à ce propos.
--
Nico,
http://astrosurf.com/nicoastro
http://nicolas.aunai.free.fr
j'ai un petit code qui m'étonne soit une fonction prenant un void*
en paramètre, lors de son appel, si je lui passe un double*, mon
compilateur dit rien ok.
soit une fonction retournant un void *, lorsque j'assigne un double*
avec le retour de cette fonction, mon compilateur ne dit rien
ici donc, pas besoin de caster ni le paramètre (en (void*)), ni le
retour de fonction (en (double*))
maintenant, on prend les même et on recommence, à la différence près
que mon argument n'est plus un void* mais un void**, et mon retour
n'est plus un void* mais aussi un void **. là plus rien ne passe
lors de l'appel de la fonction je suis obligé de caster mon double** en
void**, et lors du retour, je suis obligé de caster en double**,
pourquoi ?
pour un exemple plus parlant, considérez le code suivant :
void *
vect_new(size_t len, size_t size_type)
{
void *v = malloc(len * size_type);
return v;
}
void
vect_free(void *vect)
{
if(vect) free(vect);
}
/*declaration du vecteur
pas besoin de faire un cast (double*)*/
double *vect = vect_new(3,sizeof(double));
/*appel sans probleme a la compilation :
pas besoin de faire (void*)vect*/
vect_free(vect);
et maintenant avec des void** :
void **
mat_new(unsigned int nrow, unsigned int ncol, size_t size_type)
{
int i,j;
void **m = malloc(nrow * size_type);
if(m)
{
for(i=0; i<nrow; i++)
{
m[i] = malloc(ncol * size_type);
if(!m[i])
{
for(j=0; j<=i; j++)
free(m[i]);
free(m);
m = NULL;
}
}
}
return m;
}
void
mat_free(void **m,unsigned int nrow)
{
int i;
if(m)
{
for(i=0; i<nrow; i++)
if(m[i])
free(m[i]);
free(m);
}
}
/*declaration de la matrice*/
double **matrice = (double**)mat_new(4,3,sizeof(double));
/*appel sans probleme a la compilation : */
mat_free((void**)matrice,4);
là si je cast pas l'un et l'autre warning où se situe la
différence avec le 1er exemple ?
merci de m'éclairer à ce propos.
--
Nico,
http://astrosurf.com/nicoastro
http://nicolas.aunai.free.fr
void* est un cas particulier. Il faut un cast pour les
autres. Note que ça peut être dangereux dans les cas où
double* n'a pas la même taille que void*.
A+
--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org
pourquoi ?
c'est à dire ?
peut-on faire ce genre de fonction (allocation vecteur/matrice)
agréable sans cast ? j'ai fait ça pour éviter d'avoir une fonction par
type (vecteur de double, de int, de char etc...)
--
Nico,
http://astrosurf.com/nicoastro
http://nicolas.aunai.free.fr
Parce que la norme le dit (Gabriel te dira que le comité a
voulu innover...)
Essaie d'imaginer ce qui se passe dans ton exemple si
sizeof(void*) != sizeof(double*).
En restant conforme non: tu supposes que void* a la même
taille que les autres pointeurs ce qui n'est pas garanti.
Si cette hypothèse ne te gène pas, retourne simplement un
void*, tu pourras l'assigner sans cast à un double**.
A+
--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Ok.
Ok.
Ok.
Rien à voir.
et mon retour n'est plus un
Parce que c'est comme ça. void * est le seul type qui soit compatible
avec tous les types pointeurs sur objet. C'est garanti par la norme.
void** n'est pas du tout void*.
Moui, mais je préfèrerais que le type soit un peu moins anonyme que
void *.
http://mapage.noos.fr/emdel/tad.htm
Mais tu cherches peut être à être très générique. Admettons...
Même remarque. De plus, je préfère être explicite :
if (vect != NULL)
{
free (vect);
}
mais free(NULL); est défini (ne fait rien). Le test n'est pas exigé.
ou tout simplement (facilite la maintenance)
double *vect = vect_new (3, sizeof *vect);
ne pas oublier la vérification...
if (vect != NULL)
{
Ok.
Pourquoi des void**? Le type void** n'est pas générique. Si on t'a dit
le contraire, c'est une erreur, et celui qui a dit ça mérite le goudron
et les plumes.
Il suffit de laisser void* et c'est OK. C'est le pointeur qui va
recevoir l'adresse du bloc alloué qui fera la conversion implicite
gràce à son type.
void *
mat_new(unsigned int nrow, unsigned int ncol, size_t size_type)
double **pp = mat_new (3, 5, sizeof **pp)
par contre, pour que ça fonctionne, il faut allouer un tableau de
pointeurs et des tableaux pour chaque pointeurs, comme tu l'as fait.
Dans ce cas, la notation pp[lin][col] a un sens.
--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html
"C is a sharp tool"
C'est possible ça? Si c'est vrai, ça remet en cause beaucoup de code
qui compte là dessus...
--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html
"C is a sharp tool"
C'est faux.
void **m = malloc(nrow * sizeof (void*));
ou bien
void **m = malloc(nrow * sizeof *m);
Cela ne fonctionne que par hasard parce que dans ton exemple size_type
est sizeof(double) et dans ton système sizeof(double)==sizeof(void*).
Les fonctions mat_new et mat_free fonctionnent seulement si un void* a
la mème taille et la même représentation binaire qu'un double*.
Puisque ces deux propriétés ne sont pas imposées par la norme du
langage C la conversion n'est pas sure et il faut un cast pour dire au
compilateur "je sais que cela fonctionnne".
Si tu veux éliminer le cast lors de l'appel des fonctions et si tu es
sur que void* et double* sont identiques dans tous les système qui
font tourner ton code tu peux moodifier les fonctions:
void *
mat_new(unsigned int nrow, unsigned int ncol, size_t size_type)
{
int i,j;
void **m = malloc(nrow * sizeof *m);
...
return m;
}
void
mat_free(void *mm,unsigned int nrow)
{
void **m = mm:
...
}
--
Horst
j'ai tjrs un peu de mal a comprendre, est-ce aussi dangereux si je cast
? le cast n'est-il pas sensé convertir mes pointeurs ?
mat_free((void**)matrice,4); est-ce correct et propre ?
--
Nico,
http://astrosurf.com/nicoastro
http://nicolas.aunai.free.fr
je compile avec l'option -ansi, pourquoi mon compilateur ne me le dit
pas ?
--
Nico,
http://astrosurf.com/nicoastro
http://nicolas.aunai.free.fr
| Jean-Marc Bourguet avait soumis l'idée :
|
|
| > void* est un cas particulier.
|
| pourquoi ?
Because someone got clever.
-- Gaby
| Jean-Marc Bourguet wrote on 07/11/04 :
|
| > void* est un cas particulier. Il faut un cast pour les
| > autres. Note que ça peut être dangereux dans les cas où
| > double* n'a pas la même taille que void*.
|
| C'est possible ça?
double** n'est pas censé avoir la même tailler que void**.
| Si c'est vrai, ça remet en cause beaucoup de code
| qui compte là dessus...
Il y a beaucoup de codes douteux dans la nature ; je ne pense pas qu'il
y a une proportion significatrice qui compte sur double** ~~ void**
sans information complémentaire.
-- Gaby