[gull] Subtilité de C n° 2 : type de retour de malloc

Daniel Cordey dc at mjt.ch
Thu Apr 3 17:39:59 CEST 2008


On Thursday 03 April 2008, Marc Mongenet wrote:


> J'aurais peut-être dû présenter les deux écoles ainsi :
> p = (int*)malloc(sizeof(int));  /* école du cast explicite */
> p = malloc(sizeof(int));  /* école du cast implicite */
>
> Mais ce dernier style est vraiment criticable, car si p n'est pas
> un pointeur de int, c'est buggué et le compilateur n'a pas moyen
> de s'en rendre compte !

Oui, mais je suis aussi content de pouvoir faire mes petites magouilles avec 
le contenu de la memoire. Bien evidement, changer l'utilisation de la memoire 
reservee en depassant l'espace alloue garanti de tres gros problemes par l 
asuite... probablement lors d'un free...

> Tandis qu'avec la notation suivante, on est sûr de toujours
> transmettre à malloc la taille de l'objet pointé par p :
> p = malloc(sizeof *p);

Je prefere dire :

pointeur d'element = malloc(sizeof(element))

Bon, a ce stade, c'est sans doute une question de gout... ou une de ces 
discussions purement semantique :-) 

> La seule faiblesse de ce style est de masquer un éventuel oubli de
> l'inclusion de stdlib.h. 

Mais  on ne devrait jamais oublier stdlib.h... J'ai pour habitude 
d'inclure "my_main_include.h" qui inclut stdlib, stdio, etc. Ca m'evite de 
recrire et d'oublier pas mal de choses.

> Je suis tout à fait d'accord qu'il ne faut jamais compter sur le fait que
> sizeof(int)==sizeof(int*). Je ne me permettrais jamais une hypothèse
> aussi folle. ;-) Si vraiment on a besoin de convertir un pointeur en
> entier, il faut le convertir en unsigned long, en espérant que
> sizeof(void*)<=sizeof(unsigned long).

En fait, sizeof(void *) == sizeof(unsigned long). Ceci sur 32 et 64 bits... ce 
qui aide pas mal, sans etre completement "propre".

> par exemple le Motorola 68000 avait
> des pointeurs 32 bits mais calculait plus vite en 16 bits qu'en 32 bits
> (4 cycles au lieu de 6 pour une addition si mes souvenirs sont exacts).

et 13 mode d'adressages... d'ou moins de necessite d'alignement, donc des 
pading differents d'avec d'autres architectures.

> Ah ben je comptais écrire quelque-chose à ce sujet ;-), mais c'est une
> très longue histoire qui remonte au premier compilateur C.

:-)


> >  #define RoundN(_v_,_b_) (((unsigned int)(_v_) + _b_) & ~(_b_))
>
> Si j'ai bien compris ces macros, il faudrait un (unsigned long) ci-dessus

yes, yes, yes... j'ai ecrit cette macros au debut des annees 90 et je 
m'apercois que je ne l'avais pas changee.. horreur !

> >  Ainsi, je peux m'affranchir de l'aproxinmation de sizeof() sur les
> > structure. Et non... sizeof ne calcul pas le padding a la fin de la
> > structure... !
>
> Ben si.

Je viens de voir que ISO C le defini comme tu le dis. Mais ce n'etait 
absolument pas le cas au debut et jusqu'a cette version d'ISO. Ce changement 
pose probleme car il modifie le comportement de tous les compilateurs 
precedents cette adoption. C'est la raison pour laquelle j'avais cette macro 
qui me garantissait que la valeur retournee etait la meme, quelque soit 
l'architecture, l"OS ou le compilateur.

>> Les calculs sur des
>>  pointeurs doivent etre ramenes au 'type' du pointeur de l'architecture
>> (unsigned !).
>
> Je ne suis pas sûr que le standard donne de telles garanties.
> Pour être clair :
>
> char *p1, *p2 = malloc(1);
> unsigned long address = (unsigned long)p2;
> p1 = (char*)address;
> /* Le standard assure-t-il que p1==p2? Je n'en suis pas sûr. */

Oui, sans aucun doute. Toutefois... il ne faut pas sortir du cadre de 
l'assignation pour que cela fonctionne, car :

p2++ est different de adress++. Mais ca, nous le savons deja :-)

Par contre, je peux ecrire :

char *p1, *p2 = malloc(8);
unsigned long address = (unsigned long)p2;
printf("Result : %s", (++address) == ((unsigned long)(p2) + (unsigned long)
(4)) ? "OK" : "FAILED:);

-> OK

dc





More information about the gull mailing list