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
Yves ROMAN

Emmanuel Delahaye writes:

Jean-Marc Bourguet wrote on 08/11/04 :

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.



Peut on donc dire, pour tout type de donnée T, que :
sizeof(void *) >= sizeof(T *) ?

Et un void * peut-il aussi contenir un pointeur de fonction ?



Avatar
Jean-Marc Bourguet
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.

Et un void * peut-il aussi contenir un pointeur de fonction ?


Non. Exemple un 8086 dans un mode ou on a seul segment partage entre
la pile et les donnees mais plusieurs segments de code. Un void* fait
16 bits, un pointeur de fonction 32.

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
Marc Boyer
In article , Yves ROMAN wrote:

Emmanuel Delahaye writes:

Jean-Marc Bourguet wrote on 08/11/04 :

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.



Peut on donc dire, pour tout type de donnée T, que :
sizeof(void *) >= sizeof(T *) ?


Pourquoi ? On pourrait imaginer des bits de padding (ou de controle
de validité, on peut rèver) dans T* mais pas dans void*.

Par contre, on a sizeof(void*) == sizeof(char*), puisqu'ils
ont la même représentation (6.2.5/26)

Et un void * peut-il aussi contenir un pointeur de fonction ?


D'après mon Harbison & Steele, non: "Any pointer to an object
or an incomplete type (but /not/ a function type) can be
converted to type vod* and back without change". La norme
semble dire la même chose (6.3.2.3/1).

Marc Boyer
--
Je ne respecte plus le code de la route à vélo depuis une double fracture
due au fait que j'étais le seul à le respecter.




Avatar
Laurent Deniau
Marc Boyer wrote:
In article , Yves ROMAN wrote:


Emmanuel Delahaye writes:


Jean-Marc Bourguet wrote on 08/11/04 :

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.



Peut on donc dire, pour tout type de donnée T, que :
sizeof(void *) >= sizeof(T *) ?



Pourquoi ? On pourrait imaginer des bits de padding (ou de controle
de validité, on peut rèver) dans T* mais pas dans void*.


Dans la pratique ca parait difficile. Quel padding mettrais-tu pour T*
-> void* -> T* ? Qu'est ce que malloc renverrait?

a+, ld.





Avatar
Jean-Marc Bourguet
Laurent Deniau writes:

Pourquoi ? On pourrait imaginer des bits de padding (ou de controle
de validité, on peut rèver) dans T* mais pas dans void*.


Dans la pratique ca parait difficile. Quel padding mettrais-tu pour T* ->
void* -> T* ? Qu'est ce que malloc renverrait?


Tu peux imaginer qu'un T* comporte un pointeur brut (un void*) et un
tag (un pointeur vers une description du type). Il y a eu des
architecture a tag de meme qu'il y a eu des architectures ou pour
toute indexation il fallait passer par un descripteur mais je n'en ai
jamais regardees de pres donc je ne sais pas s'il y a eu des
compilateurs C pour elles ni comment il fonctionnait.

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
Marc Boyer
Laurent Deniau wrote:
Marc Boyer wrote:
In article , Yves ROMAN wrote:
Peut on donc dire, pour tout type de donnée T, que :
sizeof(void *) >= sizeof(T *) ?



Pourquoi ? On pourrait imaginer des bits de padding (ou de controle
de validité, on peut rèver) dans T* mais pas dans void*.


Dans la pratique ca parait difficile. Quel padding mettrais-tu pour T*
-> void* -> T* ?


J'ai pas dit que c'était du padding utile ;-)
Plus sérieusement, la conversion T* -> void* -> T* doit etre
sans effet du point de vue de la machine abstraite C. Si les
bits de padding etaient utilisés pour faire de la verif
de validite du pointeur, il parait admissible que le passage
par void* face perdre cette info.

Qu'est ce que malloc renverrait?


Oui, c'est plus chaud comme question.

Marc Boyer
--
Je ne respecte plus le code de la route à vélo depuis une double fracture
due au fait que j'étais le seul à le respecter.



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


Pourquoi ? On pourrait imaginer des bits de padding (ou de controle
de validité, on peut rèver) dans T* mais pas dans void*.


Dans la pratique ca parait difficile. Quel padding mettrais-tu pour T* ->
void* -> T* ? Qu'est ce que malloc renverrait?



Tu peux imaginer qu'un T* comporte un pointeur brut (un void*) et un
tag (un pointeur vers une description du type). Il y a eu des
architecture a tag de meme qu'il y a eu des architectures ou pour
toute indexation il fallait passer par un descripteur mais je n'en ai
jamais regardees de pres donc je ne sais pas s'il y a eu des
compilateurs C pour elles ni comment il fonctionnait.


A quoi servirait ce tag?

Si T* -> void* est dans TU1 et void* -> T* est dans TU2, quel tag a le
T* de TU2?

a+, ld.

PS. J'ai l'impression d'avoir ecrit une variante de pince-me et
pince-moi sont dans un bateau ;-)



Avatar
Charlie Gordon
"Gabriel Dos Reis" wrote in message
news:
"Charlie Gordon" writes:

| > Non, cela n'initialise pas les champs, mais met tous les bits à 0. En
| > particulier pour les flottants (float, double, ...) et les pointeurs, il
| > n'y a aucune garantie que cela corresponde à des valeurs nulles.
|
| Les initialiser à all-bit-zero, c'est toujours mieux que de les laisser à
| garbage.

ce n'est pas une meilleure stupidité -- c'est juste une autre
stupidité -- car...


Comment peux-tu soutenir une telle position !
C'est moins risqué d'avoir un contenu fixe, en l'occurrence connu, que n'importe
quel garbage variable et non reproductible !
Bien sûr le comportement sera incorrect lors de certains portages, au moins
sera-t-il très probablement systématique.
Ce qui est stupide, c'est d'utiliser des variables qui sont potentiellement
invalides.
Faire en sorte que ce type de bug soit plus facile à trouver, je ne trouve pas
cela stupide.
Les programmeurs sont *tous* beugués, et certains plus que les autres.

| Quant aux flottants, s'ils sont IEEE, 0 = all-bits-zero.

Bah non. Le format IEEE-756 n'est qu'un modèle mathématique et non une
exigence hardware. Le comité C a fait la même bêtise avant de se
rattraper.


Oui, OK, il faut être précis.
Mais connais-tu une implémentation conforme où 'all-bit-zero' n'est pas une
représentation de 0.0 ?

| Mais bien sûr on peut trouver des archi exotiques.

Je suppose que tu appelles « exotique », ce qui n'est pas encore
rentré dans ta connaissance/culture -- dont l'étendue soulève des
questions ;-)


Ethymologiquement, tu as presque raison, mais le sens ne dépend pas de la
culture du locuteur.

Exotique adj. (gr. exôtikos, étranger).
1. Qui appartient aux pays étrangers lointains, qui en provient.
2. PHYS. Dont les caractéristiques diffèrent notablement des caractéristiques
habituelles. Phénomène, particule exotique.

Les architectures que je qualifie d'exotiques sont quand même peu courantes.


[...]

| Je préfère une méthode imparfaite qui évite des problèmes qu'un
| champ de mines tout juste mentionné sur une doc.

On attend impatiemment tes tranformations en méthodes imparfaites pour
la norme C.


Vous serez aux premières loges !

D'ailleurs, comment pourrais-je participer au comité de normalisation du C ?

Chqrlie.

Avatar
Jean-Marc Bourguet
Laurent Deniau writes:

Jean-Marc Bourguet wrote:
Laurent Deniau writes:

Pourquoi ? On pourrait imaginer des bits de padding (ou de controle
de validité, on peut rèver) dans T* mais pas dans void*.


Dans la pratique ca parait difficile. Quel padding mettrais-tu pour T* ->
void* -> T* ? Qu'est ce que malloc renverrait?
Tu peux imaginer qu'un T* comporte un pointeur brut (un void*) et un

tag (un pointeur vers une description du type). Il y a eu des
architecture a tag de meme qu'il y a eu des architectures ou pour
toute indexation il fallait passer par un descripteur mais je n'en ai
jamais regardees de pres donc je ne sais pas s'il y a eu des
compilateurs C pour elles ni comment il fonctionnait.


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
trimbaler un tag specifique pour void* mais qui sait ce a quoi peuvent
penser ceux qui ont concu l'ABI -- peut-etre a des cas auxquels moi je
ne pense pas quand je fais de la speculation sur usenet.

Si T* -> void* est dans TU1 et void* -> T* est dans TU2, quel tag a
le T* de TU2?


Le meme que le T* originel. Quel probleme?

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
Laurent Deniau
Jean-Marc Bourguet wrote:
Laurent Deniau writes:


Jean-Marc Bourguet wrote:

Laurent Deniau writes:


Pourquoi ? On pourrait imaginer des bits de padding (ou de controle
de validité, on peut rèver) dans T* mais pas dans void*.


Dans la pratique ca parait difficile. Quel padding mettrais-tu pour T* ->
void* -> T* ? Qu'est ce que malloc renverrait?


Tu peux imaginer qu'un T* comporte un pointeur brut (un void*) et un
tag (un pointeur vers une description du type). Il y a eu des
architecture a tag de meme qu'il y a eu des architectures ou pour
toute indexation il fallait passer par un descripteur mais je n'en ai
jamais regardees de pres donc je ne sais pas s'il y a eu des
compilateurs C pour elles ni comment il fonctionnait.


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.

trimbaler un tag specifique pour void* mais qui sait ce a quoi peuvent
penser ceux qui ont concu l'ABI -- peut-etre a des cas auxquels moi je
ne pense pas quand je fais de la speculation sur usenet.


Je sais pas. Le seul interpreteur lisp (amateur) que j'ai ecrit etait en
C...

Si T* -> void* est dans TU1 et void* -> T* est dans TU2, quel tag a
le T* de TU2?



Le meme que le T* originel. Quel probleme?


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

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

a+, ld.