Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

cast de pointeur *, ** différence ?

114 réponses
Avatar
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

10 réponses

Avatar
Emmanuel Delahaye
Gabriel Dos Reis wrote on 08/11/04 :
Emmanuel Delahaye writes:

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 taille que void**.


C'est possible, mais c'est hors-sujet. Je parle de void* et non de
void**. Est-ce que la taille d'un double * peut être différente de
celle d'un void * ? Si c'est vrai, malloc() ne fonctionne pas.

--
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"



Avatar
Emmanuel Delahaye
Jean-Marc Bourguet wrote on 08/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?


Quoi que void* n'ait pas la meme taille que double*? Oui.


alors

double *p = malloc (sizeof *p * 12);

ne fonctionne pas ? J'arrête le C!

--
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"



Avatar
Emmanuel Delahaye
Nico wrote on 07/11/04 :
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".


je compile avec l'option -ansi, pourquoi mon compilateur ne me le dit pas ?


sans doute parce que le sur cette implémentation, il n'y a pas de
risque. Un outil d'analyse indépendant de l'implémentation comme *Lint
pourrait le dire.

--
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"


Avatar
Emmanuel Delahaye
Richard Delorme wrote on 08/11/04 :

Ou encore plus sûr :

void **m = calloc(nrow, sizeof(*m));


Pourquoi calloc() est plus sûr que malloc() ?
calloc() ne crée pas un tableau de pointeurs nuls, sauf sur les
implémentations où le pointeur nul est représenté par des bits tous nuls.


Et c'est repartit pour NULL!!!

--
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"


Avatar
Jean-Marc Bourguet
Emmanuel Delahaye writes:

C'est possible, mais c'est hors-sujet. Je parle de void*
et non de void**. Est-ce que la taille d'un double * peut
être différente de celle d'un void * ?


Oui.

Si c'est vrai, malloc() ne fonctionne pas.


Pourquoi?

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

Avatar
Jean-Marc Bourguet
Emmanuel Delahaye writes:

Jean-Marc Bourguet wrote on 08/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?



Quoi que void* n'ait pas la meme taille que double*? Oui.


alors

double *p = malloc (sizeof *p * 12);

ne fonctionne pas ?


Je ne vois pas pourquoi. La seule contrainte c'est que
void* est capable de représenter précisément tous les types
de pointeurs.

J'arrête le C!


Tu vis ta vie comme tu l'entends.

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




Avatar
Richard Delorme
Richard Delorme wrote on 08/11/04 :


Ou encore plus sûr :

void **m = calloc(nrow, sizeof(*m));



Pourquoi calloc() est plus sûr que malloc() ?
calloc() ne crée pas un tableau de pointeurs nuls, sauf sur les
implémentations où le pointeur nul est représenté par des bits tous nuls.


Et c'est repartit pour NULL!!!


Mais non, je n'ai pas parlé du pointeur nul constant.

--
Richard



Avatar
Gabriel Dos Reis
Emmanuel Delahaye writes:

| Gabriel Dos Reis wrote on 08/11/04 :
| > Emmanuel Delahaye writes:
| >
| >> 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 taille que void**.
|
| C'est possible, mais c'est hors-sujet. Je parle de void* et non de
| void**. Est-ce que la taille d'un double * peut être différente de
| celle d'un void * ?

Oui.

| Si c'est vrai, malloc() ne fonctionne pas.

Quelle est la chaîne logique d'inférences qui t'amène à cette
conclusion ?

-- Gaby
Avatar
Gabriel Dos Reis
Emmanuel Delahaye writes:

| J'arrête le C!

C'est peut-être une bonne idée.

-- Gaby
Avatar
Laurent Deniau
Emmanuel Delahaye wrote:
Jean-Marc Bourguet wrote on 08/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?



Quoi que void* n'ait pas la meme taille que double*? Oui.



alors

double *p = malloc (sizeof *p * 12);

ne fonctionne pas ? J'arrête le C!


T1* -> T2* OK si T1* contient un alignement compatible avec T2*

si sizeof(T1*) > sizeof(T2*) l'operateur de cast a le droit d'enlever
des bits de poids faible pour reduire la taille du pointeur T1* a la
taille de T2*.

si sizeof(T1*) < sizeof(T2*) l'operateur de cast a le droit d'ajouter
des bits pour agrandir la taille du pointeur T1* a la taille de T2*. Ce
qui veut dire que T1*+bits_ajoutes doit etre compatible avec T2* sinon BOUM.

par specialisation

T* -> void* OK
void* -> T* OK si void* contient un alignement compatible avec T*

parce que void* est capable de contenir tous les alignements necessaires
au C, c'est a dire qu'il a la taille maximale qu'un pointeur peut avoir.
malloc renvoie un void* compatible avec T*, qqs T.

par transition

T* -> void* -> T* OK (puisque T* -> T* OK)
T1* -> void* -> T2* OK seulement si T1* -> T2* OK

mais

void* -> T* -> void* OK seulement si void* -> T* OK

a+, ld.