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 :
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 ?
C'est bien dommage en effet. Le fait que l'on puisse caster implicitement X** et void* est une cause de bug.
void **m = malloc(nrow * size_type);
Non, c'est faux, tu devrais toujours utiliser la version plus sûre :
void **m = malloc(nrow * sizeof(*m));
Ou encore plus sûr :
void **m = calloc(nrow, sizeof(*m));
Mais tu fais en outre la supposition que void* fait la même taille que double*. C'est pas très risqué, mais sois conscient que cela peut être faux pour certains environnements.
Réciproquement, j'ai souvent pesté contre la sémantique des void* qui m'empêche d'écrire sans cast le code suivant :
void freep(void **pp) { free(*p); *p = NULL; }
char *p = malloc(1000); ... freep(&p);
En conclusion, C est trop primitif, on voudrait y rajouter juste un zeste de C++ : new, delete, des types génériques... tableaux multidimensionnels dynamiques... mais c'est un engrenage infernal ;-)
Chqrlie.
"Nico" <nicolas.aunai@free.fr> wrote in message
news:mn.3cb17d4bd687ce0d.17347@free.fr...
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 ?
C'est bien dommage en effet.
Le fait que l'on puisse caster implicitement X** et void* est une cause de bug.
void **m = malloc(nrow * size_type);
Non, c'est faux, tu devrais toujours utiliser la version plus sûre :
void **m = malloc(nrow * sizeof(*m));
Ou encore plus sûr :
void **m = calloc(nrow, sizeof(*m));
Mais tu fais en outre la supposition que void* fait la même taille que double*.
C'est pas très risqué, mais sois conscient que cela peut être faux pour certains
environnements.
Réciproquement, j'ai souvent pesté contre la sémantique des void* qui m'empêche
d'écrire sans cast le code suivant :
void freep(void **pp) {
free(*p);
*p = NULL;
}
char *p = malloc(1000);
...
freep(&p);
En conclusion, C est trop primitif, on voudrait y rajouter juste un zeste de C++
: new, delete, des types génériques... tableaux multidimensionnels
dynamiques... mais c'est un engrenage infernal ;-)
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 ?
C'est bien dommage en effet. Le fait que l'on puisse caster implicitement X** et void* est une cause de bug.
void **m = malloc(nrow * size_type);
Non, c'est faux, tu devrais toujours utiliser la version plus sûre :
void **m = malloc(nrow * sizeof(*m));
Ou encore plus sûr :
void **m = calloc(nrow, sizeof(*m));
Mais tu fais en outre la supposition que void* fait la même taille que double*. C'est pas très risqué, mais sois conscient que cela peut être faux pour certains environnements.
Réciproquement, j'ai souvent pesté contre la sémantique des void* qui m'empêche d'écrire sans cast le code suivant :
void freep(void **pp) { free(*p); *p = NULL; }
char *p = malloc(1000); ... freep(&p);
En conclusion, C est trop primitif, on voudrait y rajouter juste un zeste de C++ : new, delete, des types génériques... tableaux multidimensionnels dynamiques... mais c'est un engrenage infernal ;-)
Chqrlie.
Richard Delorme
void **m = malloc(nrow * size_type);
Non, c'est faux, tu devrais toujours utiliser la version plus sûre :
void **m = malloc(nrow * sizeof(*m));
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.
-- Richard
void **m = malloc(nrow * size_type);
Non, c'est faux, tu devrais toujours utiliser la version plus sûre :
void **m = malloc(nrow * sizeof(*m));
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.
Non, c'est faux, tu devrais toujours utiliser la version plus sûre :
void **m = malloc(nrow * sizeof(*m));
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.
-- Richard
Jean-Marc Bourguet
Gabriel Dos Reis writes:
Nico writes:
| Jean-Marc Bourguet avait soumis l'idée : | | | > void* est un cas particulier. | | pourquoi ?
Because someone got clever.
Je l'avais prevu :-)
-- Jean-Marc FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc Site de usenet-fr: http://www.usenet-fr.news.eu.org
Gabriel Dos Reis <gdr@cs.tamu.edu> writes:
Nico <nicolas.aunai@free.fr> writes:
| Jean-Marc Bourguet avait soumis l'idée :
|
|
| > void* est un cas particulier.
|
| pourquoi ?
Because someone got clever.
Je l'avais prevu :-)
--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org
| Jean-Marc Bourguet avait soumis l'idée : | | | > void* est un cas particulier. | | pourquoi ?
Because someone got clever.
Je l'avais prevu :-)
-- Jean-Marc FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc Site de usenet-fr: http://www.usenet-fr.news.eu.org
Charlie Gordon
"Richard Delorme" wrote in message news:418f2064$0$15749$
void **m = malloc(nrow * size_type);
Non, c'est faux, tu devrais toujours utiliser la version plus sûre :
void **m = malloc(nrow * sizeof(*m));
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.
Je n'ai pas dit cela.
Mais peux-tu citer une architecture où ce n'est pas vrai ?
calloc est plus sûr que malloc parce que la mémoire est initialisée à 0, ce qui rend le comportement des programmes plus reproductible dans le cas ou le programmeur "oublie" d'initialiser tout ou partie de la zone allouée. Cela permet même de ne pas avoir à initialiser les champs qui doivent êtres nuls. Cela permet aussi que les tableaux de char, qui sont souvent valués par un strcpy ne contiennent pas de résidus qui pourraient malencontreusement se propager sur disque, voire ailleurs, lors de stockages bruts de structures, une pratique peu recommandable, non portable et peu flexible, mais malheureusement assez courante.
Une bonne pratique défensive consiste à NULLifier les pointeurs après l'appel de free(). Ce n'est ni necessaire, ni suffisant pour éviter les bugs de mémoire, mais cela permet d'en attraper certains. De plus dans le code non critique, il n'est pas nécessaire de tester les pointeurs avant de les passer à free() qui accepte NULL sans sourciller. Au besoin, utiliser un wrapper dans les environnements où free() est beugué.
Realloc() resiste à ce genre de précaution : on ne sait pas toujours quelle partie initialiser à 0... Il faut dire que cette fonction est particulièrement mal famée, l'éviter est une sage précaution. Personnellement, dans les projets où c'est vraiment nécéssaire, j'utilise le wrapper suivant :
Cela évite la variable intermédiaire et le code qui la traite, qui est un nid à bugs.
Evidemment, le problème de cast implicite de X** en void** me fait vraiment chier ici aussi.
Chqrlie.
"Richard Delorme" <abulmo@nospam.fr> wrote in message
news:418f2064$0$15749$7a628cd7@news.club-internet.fr...
void **m = malloc(nrow * size_type);
Non, c'est faux, tu devrais toujours utiliser la version plus sûre :
void **m = malloc(nrow * sizeof(*m));
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.
Je n'ai pas dit cela.
Mais peux-tu citer une architecture où ce n'est pas vrai ?
calloc est plus sûr que malloc parce que la mémoire est initialisée à 0, ce qui
rend le comportement des programmes plus reproductible dans le cas ou le
programmeur "oublie" d'initialiser tout ou partie de la zone allouée. Cela
permet même de ne pas avoir à initialiser les champs qui doivent êtres nuls.
Cela permet aussi que les tableaux de char, qui sont souvent valués par un
strcpy ne contiennent pas de résidus qui pourraient malencontreusement se
propager sur disque, voire ailleurs, lors de stockages bruts de structures, une
pratique peu recommandable, non portable et peu flexible, mais malheureusement
assez courante.
Une bonne pratique défensive consiste à NULLifier les pointeurs après l'appel de
free(). Ce n'est ni necessaire, ni suffisant pour éviter les bugs de mémoire,
mais cela permet d'en attraper certains. De plus dans le code non critique, il
n'est pas nécessaire de tester les pointeurs avant de les passer à free() qui
accepte NULL sans sourciller. Au besoin, utiliser un wrapper dans les
environnements où free() est beugué.
Realloc() resiste à ce genre de précaution : on ne sait pas toujours quelle
partie initialiser à 0... Il faut dire que cette fonction est particulièrement
mal famée, l'éviter est une sage précaution. Personnellement, dans les projets
où c'est vraiment nécéssaire, j'utilise le wrapper suivant :
"Richard Delorme" wrote in message news:418f2064$0$15749$
void **m = malloc(nrow * size_type);
Non, c'est faux, tu devrais toujours utiliser la version plus sûre :
void **m = malloc(nrow * sizeof(*m));
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.
Je n'ai pas dit cela.
Mais peux-tu citer une architecture où ce n'est pas vrai ?
calloc est plus sûr que malloc parce que la mémoire est initialisée à 0, ce qui rend le comportement des programmes plus reproductible dans le cas ou le programmeur "oublie" d'initialiser tout ou partie de la zone allouée. Cela permet même de ne pas avoir à initialiser les champs qui doivent êtres nuls. Cela permet aussi que les tableaux de char, qui sont souvent valués par un strcpy ne contiennent pas de résidus qui pourraient malencontreusement se propager sur disque, voire ailleurs, lors de stockages bruts de structures, une pratique peu recommandable, non portable et peu flexible, mais malheureusement assez courante.
Une bonne pratique défensive consiste à NULLifier les pointeurs après l'appel de free(). Ce n'est ni necessaire, ni suffisant pour éviter les bugs de mémoire, mais cela permet d'en attraper certains. De plus dans le code non critique, il n'est pas nécessaire de tester les pointeurs avant de les passer à free() qui accepte NULL sans sourciller. Au besoin, utiliser un wrapper dans les environnements où free() est beugué.
Realloc() resiste à ce genre de précaution : on ne sait pas toujours quelle partie initialiser à 0... Il faut dire que cette fonction est particulièrement mal famée, l'éviter est une sage précaution. Personnellement, dans les projets où c'est vraiment nécéssaire, j'utilise le wrapper suivant :
Cela évite la variable intermédiaire et le code qui la traite, qui est un nid à bugs.
Evidemment, le problème de cast implicite de X** en void** me fait vraiment chier ici aussi.
Chqrlie.
Horst Kraemer
Gabriel Dos Reis wrote:
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 tailler que void**.
Oui, mais le problème du code présenté est plutot la taille de void* vs. double* et non la taille de void** vs. double** ;-)
-- Horst
Gabriel Dos Reis <gdr@cs.tamu.edu> wrote:
Emmanuel Delahaye <emdel@YOURBRAnoos.fr> 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 tailler que void**.
Oui, mais le problème du code présenté est plutot la taille de void*
vs. double* et non la taille de void** vs. double** ;-)
| 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**.
Oui, mais le problème du code présenté est plutot la taille de void* vs. double* et non la taille de void** vs. double** ;-)
-- Horst
Jean-Marc Bourguet
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?
Quoi que void* n'ait pas la meme taille que double*? Oui.
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
Emmanuel Delahaye <emdel@YOURBRAnoos.fr> 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?
Quoi que void* n'ait pas la meme taille que double*? Oui.
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
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.
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
Marc Boyer
In article , Jean-Marc Bourguet wrote:
Nico writes:
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 ?
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*.
Et ? Le compilateur n'a pas à charge de faire la conversion binaire qui va bien ? Tu parles de quel cas là, void* ou void** ?
Pour être plus clair: soit la fonction void foo(void*); est-ce que je peux l'appeller avec double *p= &qui_va_bien; foo(p); ou est-ce qu'il faut explicitement faire foo( (void*) p );
Merci, 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.
In article <87sm7lh3dz.fsf@news.bourguet.org>, Jean-Marc Bourguet wrote:
Nico <nicolas.aunai@free.fr> writes:
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 ?
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*.
Et ? Le compilateur n'a pas à charge de faire la conversion
binaire qui va bien ?
Tu parles de quel cas là, void* ou void** ?
Pour être plus clair: soit la fonction
void foo(void*);
est-ce que je peux l'appeller avec
double *p= &qui_va_bien;
foo(p);
ou est-ce qu'il faut explicitement faire
foo( (void*) p );
Merci,
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.
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 ?
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*.
Et ? Le compilateur n'a pas à charge de faire la conversion binaire qui va bien ? Tu parles de quel cas là, void* ou void** ?
Pour être plus clair: soit la fonction void foo(void*); est-ce que je peux l'appeller avec double *p= &qui_va_bien; foo(p); ou est-ce qu'il faut explicitement faire foo( (void*) p );
Merci, 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.
Jean-Marc Bourguet
Marc Boyer writes:
In article , Jean-Marc Bourguet wrote:
Nico writes:
[cast de void** en double**] Note que ça peut être dangereux dans les cas où double* n'a pas la
même taille que void*.
Et ? Le compilateur n'a pas à charge de faire la conversion binaire qui va bien ?
Le cast de void** en double** ne va pas aller changer le tableau intermediaire. Reprenons le coeur de ce que je pensais qu'avait fait Nico (voir plus bas, il y a un probleme en plus dans ce qu'a fait Nico):
void** tab = malloc(dim1 * sizeof(void*)); for (int i = 0; i < dim1; ++i) { tab[i] = malloc(dim2 * sizeof(double)); }
double** theTab = (double**) tab;
Ce cast va ajuster la valeur de tab comme il faut, mais pas celle de *tab: or on y a stocke des pointeurs vers void, pas des pointeurs vers double et rien ne garanti qu'ils ont le meme format ou meme la meme taille. (En pratique je ne connais pas d'architecture recente ou ca va poser un probleme.)
En realite, Nico n'utilise pas sizeof(void*) pour la premiere allocation mais sizeof(double). Il est vraissemblable qu'il ne fait qu'allouer trop car je ne connais pas d'architecture (recente ou non) ou sizeof(double) < sizeof(void*). Mais s'il y en avait une...
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
Marc Boyer <Marc.Boyer@enseeiht.yahoo.fr.invalid> writes:
In article <87sm7lh3dz.fsf@news.bourguet.org>, Jean-Marc Bourguet wrote:
Nico <nicolas.aunai@free.fr> writes:
[cast de void** en double**]
Note que ça peut être dangereux dans les cas où double* n'a pas la
même taille que void*.
Et ? Le compilateur n'a pas à charge de faire la conversion binaire
qui va bien ?
Le cast de void** en double** ne va pas aller changer le tableau
intermediaire. Reprenons le coeur de ce que je pensais qu'avait fait
Nico (voir plus bas, il y a un probleme en plus dans ce qu'a fait
Nico):
void** tab = malloc(dim1 * sizeof(void*));
for (int i = 0; i < dim1; ++i) {
tab[i] = malloc(dim2 * sizeof(double));
}
double** theTab = (double**) tab;
Ce cast va ajuster la valeur de tab comme il faut, mais pas celle de
*tab: or on y a stocke des pointeurs vers void, pas des pointeurs vers
double et rien ne garanti qu'ils ont le meme format ou meme la meme
taille. (En pratique je ne connais pas d'architecture recente ou ca
va poser un probleme.)
En realite, Nico n'utilise pas sizeof(void*) pour la premiere
allocation mais sizeof(double). Il est vraissemblable qu'il ne fait
qu'allouer trop car je ne connais pas d'architecture (recente ou non)
ou sizeof(double) < sizeof(void*). Mais s'il y en avait une...
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
[cast de void** en double**] Note que ça peut être dangereux dans les cas où double* n'a pas la
même taille que void*.
Et ? Le compilateur n'a pas à charge de faire la conversion binaire qui va bien ?
Le cast de void** en double** ne va pas aller changer le tableau intermediaire. Reprenons le coeur de ce que je pensais qu'avait fait Nico (voir plus bas, il y a un probleme en plus dans ce qu'a fait Nico):
void** tab = malloc(dim1 * sizeof(void*)); for (int i = 0; i < dim1; ++i) { tab[i] = malloc(dim2 * sizeof(double)); }
double** theTab = (double**) tab;
Ce cast va ajuster la valeur de tab comme il faut, mais pas celle de *tab: or on y a stocke des pointeurs vers void, pas des pointeurs vers double et rien ne garanti qu'ils ont le meme format ou meme la meme taille. (En pratique je ne connais pas d'architecture recente ou ca va poser un probleme.)
En realite, Nico n'utilise pas sizeof(void*) pour la premiere allocation mais sizeof(double). Il est vraissemblable qu'il ne fait qu'allouer trop car je ne connais pas d'architecture (recente ou non) ou sizeof(double) < sizeof(void*). Mais s'il y en avait une...
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
Marc Boyer
In article , Jean-Marc Bourguet wrote:
Marc Boyer writes:
In article , Jean-Marc Bourguet wrote:
Nico writes:
[cast de void** en double**] Note que ça peut être dangereux dans les cas où double* n'a pas la
même taille que void*.
Et ? Le compilateur n'a pas à charge de faire la conversion binaire qui va bien ?
Le cast de void** en double** ne va pas aller changer le tableau intermediaire. Reprenons le coeur de ce que je pensais qu'avait fait Nico (voir plus bas, il y a un probleme en plus dans ce qu'a fait Nico):
OK, c'était void** vs double**
void** tab = malloc(dim1 * sizeof(void*)); for (int i = 0; i < dim1; ++i) { tab[i] = malloc(dim2 * sizeof(double)); }
double** theTab = (double**) tab;
Ce cast va ajuster la valeur de tab comme il faut, mais pas celle de *tab: or on y a stocke des pointeurs vers void, pas des pointeurs vers double et rien ne garanti qu'ils ont le meme format ou meme la meme taille. (En pratique je ne connais pas d'architecture recente ou ca va poser un probleme.)
Ouaip.
Merci, 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.
In article <pxbekj4sl6n.fsf@news.bourguet.org>, Jean-Marc Bourguet wrote:
Marc Boyer <Marc.Boyer@enseeiht.yahoo.fr.invalid> writes:
In article <87sm7lh3dz.fsf@news.bourguet.org>, Jean-Marc Bourguet wrote:
Nico <nicolas.aunai@free.fr> writes:
[cast de void** en double**]
Note que ça peut être dangereux dans les cas où double* n'a pas la
même taille que void*.
Et ? Le compilateur n'a pas à charge de faire la conversion binaire
qui va bien ?
Le cast de void** en double** ne va pas aller changer le tableau
intermediaire. Reprenons le coeur de ce que je pensais qu'avait fait
Nico (voir plus bas, il y a un probleme en plus dans ce qu'a fait
Nico):
OK, c'était void** vs double**
void** tab = malloc(dim1 * sizeof(void*));
for (int i = 0; i < dim1; ++i) {
tab[i] = malloc(dim2 * sizeof(double));
}
double** theTab = (double**) tab;
Ce cast va ajuster la valeur de tab comme il faut, mais pas celle de
*tab: or on y a stocke des pointeurs vers void, pas des pointeurs vers
double et rien ne garanti qu'ils ont le meme format ou meme la meme
taille. (En pratique je ne connais pas d'architecture recente ou ca
va poser un probleme.)
Ouaip.
Merci,
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.
[cast de void** en double**] Note que ça peut être dangereux dans les cas où double* n'a pas la
même taille que void*.
Et ? Le compilateur n'a pas à charge de faire la conversion binaire qui va bien ?
Le cast de void** en double** ne va pas aller changer le tableau intermediaire. Reprenons le coeur de ce que je pensais qu'avait fait Nico (voir plus bas, il y a un probleme en plus dans ce qu'a fait Nico):
OK, c'était void** vs double**
void** tab = malloc(dim1 * sizeof(void*)); for (int i = 0; i < dim1; ++i) { tab[i] = malloc(dim2 * sizeof(double)); }
double** theTab = (double**) tab;
Ce cast va ajuster la valeur de tab comme il faut, mais pas celle de *tab: or on y a stocke des pointeurs vers void, pas des pointeurs vers double et rien ne garanti qu'ils ont le meme format ou meme la meme taille. (En pratique je ne connais pas d'architecture recente ou ca va poser un probleme.)
Ouaip.
Merci, 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.
Richard Delorme
"Richard Delorme" wrote in message news:418f2064$0$15749$
void **m = malloc(nrow * size_type);
Non, c'est faux, tu devrais toujours utiliser la version plus sûre :
void **m = malloc(nrow * sizeof(*m));
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.
Je n'ai pas dit cela.
Mais peux-tu citer une architecture où ce n'est pas vrai ?
http://www.eskimo.com/~scs/C-faq/q5.17.html
calloc est plus sûr que malloc parce que la mémoire est initialisée à 0, ce qui rend le comportement des programmes plus reproductible dans le cas ou le programmeur "oublie" d'initialiser tout ou partie de la zone allouée. Cela permet même de ne pas avoir à initialiser les champs qui doivent êtres nuls.
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.
Cela permet aussi que les tableaux de char, qui sont souvent valués par un strcpy ne contiennent pas de résidus qui pourraient malencontreusement se propager sur disque, voire ailleurs, lors de stockages bruts de structures, une pratique peu recommandable, non portable et peu flexible, mais malheureusement assez courante.
C'est marrant que tu critiques strncpy alors qu'il a ce comportement...
Une bonne pratique défensive consiste à NULLifier les pointeurs après l'appel de free(). Ce n'est ni necessaire, ni suffisant pour éviter les bugs de mémoire, mais cela permet d'en attraper certains. De plus dans le code non critique, il n'est pas nécessaire de tester les pointeurs avant de les passer à free() qui accepte NULL sans sourciller. Au besoin, utiliser un wrapper dans les environnements où free() est beugué.
Realloc() resiste à ce genre de précaution : on ne sait pas toujours quelle partie initialiser à 0... Il faut dire que cette fonction est particulièrement mal famée, l'éviter est une sage précaution. Personnellement, dans les projets où c'est vraiment nécéssaire, j'utilise le wrapper suivant :
memset() souffre évidemment du même problème que calloc().
-- Richard
"Richard Delorme" <abulmo@nospam.fr> wrote in message
news:418f2064$0$15749$7a628cd7@news.club-internet.fr...
void **m = malloc(nrow * size_type);
Non, c'est faux, tu devrais toujours utiliser la version plus sûre :
void **m = malloc(nrow * sizeof(*m));
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.
Je n'ai pas dit cela.
Mais peux-tu citer une architecture où ce n'est pas vrai ?
http://www.eskimo.com/~scs/C-faq/q5.17.html
calloc est plus sûr que malloc parce que la mémoire est initialisée à 0, ce qui
rend le comportement des programmes plus reproductible dans le cas ou le
programmeur "oublie" d'initialiser tout ou partie de la zone allouée. Cela
permet même de ne pas avoir à initialiser les champs qui doivent êtres nuls.
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.
Cela permet aussi que les tableaux de char, qui sont souvent valués par un
strcpy ne contiennent pas de résidus qui pourraient malencontreusement se
propager sur disque, voire ailleurs, lors de stockages bruts de structures, une
pratique peu recommandable, non portable et peu flexible, mais malheureusement
assez courante.
C'est marrant que tu critiques strncpy alors qu'il a ce comportement...
Une bonne pratique défensive consiste à NULLifier les pointeurs après l'appel de
free(). Ce n'est ni necessaire, ni suffisant pour éviter les bugs de mémoire,
mais cela permet d'en attraper certains. De plus dans le code non critique, il
n'est pas nécessaire de tester les pointeurs avant de les passer à free() qui
accepte NULL sans sourciller. Au besoin, utiliser un wrapper dans les
environnements où free() est beugué.
Realloc() resiste à ce genre de précaution : on ne sait pas toujours quelle
partie initialiser à 0... Il faut dire que cette fonction est particulièrement
mal famée, l'éviter est une sage précaution. Personnellement, dans les projets
où c'est vraiment nécéssaire, j'utilise le wrapper suivant :
"Richard Delorme" wrote in message news:418f2064$0$15749$
void **m = malloc(nrow * size_type);
Non, c'est faux, tu devrais toujours utiliser la version plus sûre :
void **m = malloc(nrow * sizeof(*m));
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.
Je n'ai pas dit cela.
Mais peux-tu citer une architecture où ce n'est pas vrai ?
http://www.eskimo.com/~scs/C-faq/q5.17.html
calloc est plus sûr que malloc parce que la mémoire est initialisée à 0, ce qui rend le comportement des programmes plus reproductible dans le cas ou le programmeur "oublie" d'initialiser tout ou partie de la zone allouée. Cela permet même de ne pas avoir à initialiser les champs qui doivent êtres nuls.
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.
Cela permet aussi que les tableaux de char, qui sont souvent valués par un strcpy ne contiennent pas de résidus qui pourraient malencontreusement se propager sur disque, voire ailleurs, lors de stockages bruts de structures, une pratique peu recommandable, non portable et peu flexible, mais malheureusement assez courante.
C'est marrant que tu critiques strncpy alors qu'il a ce comportement...
Une bonne pratique défensive consiste à NULLifier les pointeurs après l'appel de free(). Ce n'est ni necessaire, ni suffisant pour éviter les bugs de mémoire, mais cela permet d'en attraper certains. De plus dans le code non critique, il n'est pas nécessaire de tester les pointeurs avant de les passer à free() qui accepte NULL sans sourciller. Au besoin, utiliser un wrapper dans les environnements où free() est beugué.
Realloc() resiste à ce genre de précaution : on ne sait pas toujours quelle partie initialiser à 0... Il faut dire que cette fonction est particulièrement mal famée, l'éviter est une sage précaution. Personnellement, dans les projets où c'est vraiment nécéssaire, j'utilise le wrapper suivant :