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
Gabriel Dos Reis
Marc Boyer writes:

| Gabriel Dos Reis wrote:
| > Jean-Marc Bourguet writes:
| >
| >| Yves ROMAN writes:
| >|
| >| > > 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.
| >| >
| >| > Peut on donc dire, pour tout type de donnée T, que :
| >| > sizeof(void *) >= sizeof(T *) ?
| >|
| >| Ce n'est pas formel mais je ne vois pas de plateforme ou il aurait ete
| >| raisonnable que ce ne soit pas le cas.
| >
| > Je crois qu'il y a des indications dans la norme qu'on peut déduire
| >
| > sizeof (void*) == sizeof (char*)
|
| 6.2.5/26
| A pointer to void shall have the same representation and alignment
| requirements as a pointer to a character type.
|
| > && sizeof (void*) >= sizeof (T*)
|
| Ca, j'ai pas vu.

Tu peux caster T* en void* sans perte d'information.

-- Gaby
Avatar
Laurent Deniau
Jean-Marc Bourguet wrote:
Laurent Deniau writes:


A quoi servirait ce tag?


A ce qu'on veut. Imagine une machine concue pour executer du lisp
avec de l'assistance hard, le tag peut etre necessaire pour faire qqch
du pointeur mais pas pour trimbaler un void*. J'aurais tendance a


Il me semble que sur Lisp, les types de base ont chacun un tas
specialise donc il n'est pas necessaire d'utiliser un tag pour
determiner le type du pointeur.



C'est une implementation possible. Une autre est d'utiliser le fait
que les pointeurs sont alignes et donc mettre un tag dans les bits de
poids faible.


Le meme que le T* originel. Quel probleme?


Quel est le tag du T* originel issu de malloc()?



malloc renvoie un void*, donc sans tag.


Comment T* et void* peuvent avoir des tailles differentes dans ce cas?



t* est un struct {
tag* the_tag;
void* the_value;
};

Un cast met le tag adequat.


Si le tag correspond toujours au type du pointeur, quel est l'interet?
Le C connait deja le type du pointeur.

a+, ld.




Avatar
Gabriel Dos Reis
"Antoine Leca" writes:

| En , Gabriel Dos Reis va escriure:
| > Je crois qu'il y a des indications dans la norme qu'on peut déduire
| >
| > sizeof (void*) >= sizeof (T*)
| >
| > parce que void* doit pouvoir contenir des pointeurs sur n'importe quel
| > objet.
|
| Penses-tu à 6.3.2.3p1
|
| A pointer to /void/ may be converted to or from a pointer to any
| incomplete or object type. A pointer to any incomplete or object
| type may be converted to a pointer to /void/ and back again; the
| result shall compare equal to the original pointer.
|
| Autrement dit ce n'est pas symétrique, la conversion void* => T* ne peut pas
| ajouter d'information extérieure (entropie).

Oui, c'est à cela que je pensais.

| Cela étant, cela n'est pas une contrainte sur la représentation des objets.
| Comme le disait Jean-Marc, on peut y ajouter des informations de validation
| du type T*, par exemple; ou un pointeur vers une fonction de debug qui sait
| afficher le contenu de l'objet pointé. Vois pas le souci.

Oui, mais je ne vois pas comment pourrais arriver si

sizeof (void*) < sizeof (T*)

(OK, l'usage de sizeof n'est pas adéquat, il faudrait parler de nombre
de bits significatifs, mais je crois que tu vois ce que je vuex dire).

-- Gaby
Avatar
Jean-Marc Bourguet
Laurent Deniau writes:

Si le tag correspond toujours au type du pointeur, quel est
l'interet?


Correspondre au format defini par le hard qui a besoin du tag?

J'ai pas ecrit que l'interet etait profond, simplement que ca me
semblait une implementation conforme.

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
Emmanuel Delahaye
Yves ROMAN wrote on 09/11/04 :
Et un void * peut-il aussi contenir un pointeur de fonction ?


Ce n'est pas garanti. (Il y a des exemples célèbres en x86 mode réel)

--
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
Gabriel Dos Reis wrote on 09/11/04 :
Je crois qu'il y a des indications dans la norme qu'on peut déduire

sizeof (void*) == sizeof (char*) && sizeof (void*) >= sizeof (T*)

parce que void* doit pouvoir contenir des pointeurs sur n'importe quel
objet. Je crois également que C99 demande


Ah, voilà qui est plus clair. Ca veux dire que pour allouer un tableau
de pointeurs générique, on doit faire

void *a = malloc (sizeof *a *taille)

Un tel tableau est alors capable de recevoir les adresses de n'importe
quel objet. On est bien d'accord ?

sizeof (*S) == sizeof (T*), forall tags S, T.


J'ai rien compris. Pas assez neurones...

--
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
Gabriel Dos Reis wrote on 09/11/04 :
Emmanuel Delahaye writes:

J'arrête le C!


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

-- Gaby


... toujours sympa.

(Ton séparateur de .sig est invalide. Oui, je sais, tu t'en fous...)

--
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
Antoine Leca
En , Gabriel Dos Reis va escriure:
Cela étant, cela n'est pas une contrainte sur la représentation des
objets. Comme le disait Jean-Marc, on peut y ajouter des
informations de validation du type T*, par exemple; ou un pointeur
vers une fonction de debug qui sait afficher le contenu de l'objet
pointé. Vois pas le souci.


Oui, mais je ne vois pas comment pourrais arriver si

sizeof (void*) < sizeof (T*)

(OK, l'usage de sizeof n'est pas adéquat, il faudrait parler de nombre
de bits significatifs, mais je crois que tu vois ce que je vuex dire).


Représentation d'un void *

struct void_ptr {
unsigned adresse;
}


Représentation d'un T*

struct autre_ptr {
unsigned adresse;
void (*helper)(struct autre_ptr*, FILE*);
}

Et le débogueur sait faire tout seul pour void*, char* et les dérivés
immédiats.

Une autre idée du même bois:

Représentation d'un void *

struct void_ptr {
unsigned adresse;
void (*(*vmt)[])();
}


Représentation d'un T*

struct autre_ptr {
unsigned adresse;
void (*(*vmt)[])();
unsigned taille_objet_pointé;
}


Inutile de préciser que je n'ai pas testé, j'élucubre, dans la grande
tradition des Antoine!


Avatar
Nico
Il se trouve que Stephane Legras-Decussy a formulé :

quelqu'un peut expliquer le probleme comme pour un gamin
de 5 ans ?


<HS>
t'aurais dit "6 ans" ça me faisait penser a une réplique de film, mais
je trouve plus lequel, tu sais ? (c pas une blague)
</HS>

--
Nico,
http://astrosurf.com/nicoastro
http://nicolas.aunai.free.fr

Avatar
Horst Kraemer
Emmanuel Delahaye wrote:

Gabriel Dos Reis wrote on 09/11/04 :
Je crois qu'il y a des indications dans la norme qu'on peut déduire

sizeof (void*) == sizeof (char*) && sizeof (void*) >= sizeof (T*)

parce que void* doit pouvoir contenir des pointeurs sur n'importe quel
objet. Je crois également que C99 demande


Ah, voilà qui est plus clair. Ca veux dire que pour allouer un tableau
de pointeurs générique, on doit faire

void *a = malloc (sizeof *a *taille)

Un tel tableau est alors capable de recevoir les adresses de n'importe
quel objet. On est bien d'accord ?


Non. Il n'y a rien dans la norme qui interdit que la taille d'un T*
pourrait être supérieure à la taille d'un void*. Le fait qu'un void*
doit être capable de stocker l'information "adresse" d'un T* ne
l'empêche pas le T* de stocker une information spéfifique pour son
type.

--
Horst