;) si ton analyse et ta conception sont bien faits, à la limite tu peux rajouter des propriétés à l'objet, mais pas son type... :PCitation:
Envoyé par Médinoc
Version imprimable
;) si ton analyse et ta conception sont bien faits, à la limite tu peux rajouter des propriétés à l'objet, mais pas son type... :PCitation:
Envoyé par Médinoc
On n'est jamais à l'abri de la nouveauté.
- Il peut un jour être nécessaire de "scinder un type en deux"; voire en C++, de jouer avec l'héritage, s'apercevoir que les fonctions exposées par la classe mère sont insuffisantes pour les nouveaux besoins et qu'il faudra désormais travailler directement avec le type dérivé, etc.
- Ou bien, directement s'il est question d'un type entier, passer à un type entier plus grand;
- Ou encore partir d'un programme utilisant des char et le mettre à jour pour supporter unicode (passer aux wchar_t ou aux TCHAR sous Windows).
Voici une question de débutant, que je suis d'ailleurs, mais en quoi le fait de caster NULL ici lui confère un type fort. Lorsqu'un écrit:Citation:
Envoyé par Médinoc
Triangle *p_triangle = NULL;
On a un cast implicite (void *) -> (Triangle *) autorisé en C. Non?
Thierry
Oui.Citation:
Envoyé par mujigka
Le cast de NULL n'est pas obligatoire.
Mais il arrive parfois de rencontrer ce type de notation car certaines personnes y voient un interet documentaire (personellement je ne partage pas cette opinion).
J'ai egalement entendu parler, et Souviron le confirme dans son message, d'anciens compilateurs presentant des problemes de type sur NULL. Dans ce cas, le cast n'a plus de raison d'etre mais peut etre rencontre dans du code ancien ou ecrit par des personnes ayant pris cette habitude.
Pas forcément si ancien que ça.... ;)Citation:
Envoyé par gl
Exemple tiré de XFree-86 :
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 XFREE86_Region XFREE86_XCreateRegion() { XFREE86_Region temp; if (! (temp = ( XFREE86_Region )Xmalloc( (unsigned) sizeof( REGION )))) return (XFREE86_Region) NULL; if (! (temp->rects = ( BOX * )Xmalloc( (unsigned) sizeof( BOX )))) { Xfree((char *) temp); return (XFREE86_Region) NULL; } .............. if (! (dstrgn->rects = (BOX *) Xrealloc((char *) dstrgn->rects, (unsigned) rgn->numRects * (sizeof(BOX))))) { ............. if ((top != bot) && (nonOverlap1Func != (void (*)())NULL)) { (* nonOverlap1Func) (newReg, r1, r1BandEnd, top, bot); }
et pour la date :
euhhh ;) :yaisse2:Code:
1
2
3
4
5 Copyright 1987, 1988, 1998 The Open Group All Rights Reserved.
A l'echelle de l'informatique, 10 ans (voire 20 si ce code date de 87) c'est plutot ancien (et pre-C99).Citation:
Envoyé par souviron34
Et puis on peu aussi rentre dans la seconde categorie : "ou ecrit par des personnes ayant pris cette habitude.".
Sans compter sur les personnes qui trouvent une valeur documentaire a ce genre de pratique.
Oui, mais on n'a pas de cast implicite (Triangle *) -> (NimporteQuoi *) ;)Citation:
Envoyé par mujigka
Donc oui, le cast est principalement à des fins documentaires, et pour être sûr qu'on sait toujours de quoi on parle, ce qu'on passe (ou plutôt ne passe pas) à une fonction, etc.
Absolument d'accord avec la deuxième partie..Citation:
Envoyé par gl
Cependant en ce qui concerne les "10 ans (voire 20 ...) etc.." , je ne suis pas d'accord.. J'ai démarré un débat sur le forum général, mais personne n'a répondu. Mais je pense que les décideurs et chefs de projets en info font un peu aussi du "jeunisme", et suivent d'un peu trop près la mode...
Je viens d'un milieu où les projets peuvent mettre 30 ans à être écrits et peuvent avoir une durée de vie de 50 ans (voir la station spatiale orbitale Freedom) : 80 000 programmeurs de 50 pays pendant 25 ans. Durée de vie prévue en orbite : minimum 40 ans. 10 ans uniquement consacré à rédiger les normes de programmation pour chaque langage.
Je respecte la pensée, et je tente de m'inscire dans la même lignée. Mon code devrait faire une fonctionalité que l'informatique peut faire mieux et plus rapidement que l'humain, le déchargeant ainsi d'une partie souvent fastidieuse de son travail. Cependant j'aime à croire que ce que je fais ne vas pas partir à la poubelle dans les 3 ans.... Mais je me fais peut-être des illusions :cry:
Plus prosaiquement, pour ne citer que quelques exemples (et en remontant dans le temps) qui ont toujours leurs usages aujourd'hui :
HTTP : code C écrit en 1992
XWindow : code C écrit entre 1979 et 1984
.... : (je me souviens plus le nom là tout de suite) : bibliothèque de maths du CERN code Fortran écrit entre 1963 et 1978 (environ 20 millions de lignes)
(si ça vous intéresse je vous retrouverai le nom demain).
En résumé, oui au progrès, non à l'obscolescence (?) à tout prix....
PS: malgré tous les progrès techniques dans tous les matériaux, un ébéniste qui fait une armoire en bois, son armoire dure beaucoup plus longtemps qu'une amoire IKEA ;) (et sans compter (je suis dans le Sud :) ) les acqueducs romains, un peu plus solides que les tours de la Défense...)
C'est vrai! Merci Médinoc...Citation:
Envoyé par Médinoc
Thierry
Pas portable. Ce nom est réservé à l'implémentation :Citation:
Envoyé par souviron34
http://emmanuel-delahaye.developpez....htm#id_reserve
Selon mes regles de codage, ça donnerait ça :
Code:
1
2
3
4
5
6
7
8
9
10
11 typedef struct triangle { int s1; int s2; int s3; struct triangle *p_next; struct triangle *p_prev; } triangle_s;
Ca sert à quoi tous ces cast ?Citation:
Envoyé par souviron34
D'autre part, calloc() (all-bit-to-zero) n'est pas une manière portable d'initialiser les éléments d'une structure à 0.Code:
1
2
3
4
5
6
7
8
9
10
11 Triangle *Triangles = NULL; Triangle *elt = NULL ; Triangle *next = NULL ; ...... elt = calloc (1, sizeof(Triangle) ); if ( elt == NULL ) { if ( next != NULL )
Les casts de NULL, on en a discuté plus haut (fins documentaires, mais devrait être plus centralisé selon moi).
Celui de calloc() par contre est inapproprié.
Bah, du mauvais code ou du code écrit par des gens qui mélangent C et C++, on en trouve partout... Ca ne sert à rien de citer du code open source. C'est probablement du code qui fonctionne, mais ça n'a jamais été une référence en matière de codage. En quelques lignes :Citation:
Envoyé par souviron34
- déclaration de la fonction non prototypale (manque void)
- pointeurs cachés
- définitions redondantes : XFREE86_Region est visiblement *REGION
- manque d'homogénéité : cast sans *, cast avec *...
- casts inutiles
- ! au lieu de == NULL
- affectaton dans un if()
- return multiples
je m'arrête là, parce que pour 10 lignes de code, je trouve que ça fait beaucoup...
bref, ce code ne passe pas le moindre contrôle de qualité en entreprise.
Je ne vois pas ce que ça documente. Et puis NULL est compatible avec tous les types pointeur sur objet, alors qu'est-ce que change ?Citation:
Envoyé par Médinoc
Apparement si, la première allocation est bien libérée.Citation:
Envoyé par Emmanuel Delahaye
:oops: Exact, c'est tellement ilisible que je ne l'avais pas vu (on va dire ça comme ça :aie: )Citation:
Envoyé par crocodilex
Comme dit plus haut, c'est justement le problème.Citation:
Envoyé par Emmanuel Delahaye
Utiliser des #define avec un NULL casté donne des NULL typés.
Bien sûr, caster directement dans chaque utilisation est stupide à mon goût...
J'ai toujours pas compris en quoi c'était un problème. Tu peux donner un exemple de problème ?Citation:
Envoyé par Médinoc
A quoi ça sert des NULL typés ? Dans un contexte pointeur, NULL a la même sémantique quelque soit le type, je ne vois pas contre quelle erreur on cherche à se défendre...Citation:
Utiliser des #define avec un NULL casté donne des NULL typés.
Bien sûr, caster directement dans chaque utilisation est stupide à mon goût...
Je ne suis pas contre, mais je veux juste qu'on m'explique.
Je ne connais personnellement qu'un cas où il faut mettre un cast à NULL, c'est quand c'est un paramètre de fonction variadic, parce que dans ce cas, le contexte pointeur n'est pas implicite.
Code:printf ("%p\n", (void *) NULL);
En effet, je viens de voir la faille de mon raisonnement.
Je pensais utiliser des NULL typés pour sans cesse se rappeler qu'un paramètre à NULL était supposé être un pointeur de tel type, garder le type de variable à l'esprit en permanence, mais cela induit en fait un coût de maintenance supplémentaire si un type est modifié (comme les casts, en fait).
Donc en fait, utiliser des NULL typés est absolument inutile, mon raisonnement dessus vient de s'écrouler.
Edit : AH SI ! Je me souviens pourquoi j'avais fait ça, c'est à cause du C++, et cela évitait tout risque d'affecter un NULL à autre chose qu'un pointeur (en C, NULL est la plupart du temps (mais non-garanti) déjà un void*, alors qu'en C++, c'est généralement un bète 0). Je ne supporte pas ceux qui utilisent allègrement 0 pour NULL, voire l'inverse en C++.
bon.. Je veux bien que C99 prenne en compte certaines choses.
Mais certaines choses sont dans la définition même de C, car MACHINE-dépendantes.
Je vous place donc ici quelques extraits de K&R pour :
- les cast
- les sizeof de variable ou de type...
Et de plus, je peux vous assurez que pour les free, si vous comptez sur le fait qu'un free(NULL) ne fera rien, eh bien bonne chance.....
http://cjoint.com/?cnpKxor2Qp
Wouah ! Le vieux scan ! Ta version du K&R est complètement dépassée (original : 1978)!Citation:
Envoyé par souviron34
Je rappelle que le K&R2 qui correspond aux drafts de C89 (C8x) est sorti en 1988. Complété de son errata, c'est le livre de référence qui correspond à l'immense majorité du C utilisé actuellement. Le C K&R (ou pré-ANSI) est conservé pour la maintenance des anciens programmes, mais il est poubellisé au fur et à mesure qu'il est remplacé par du C89 (ANSI) / C90 (ISO), voire C99 de nos jours.
OK, sur les implémentations non conformes à C89 (aka pré-ANSI), il peut y avoir des problèmes avec free(NULL). (personnellement, en principe, je n'appelle pas free(NULL), perte de temps).Citation:
Et de plus, je peux vous assurez que pour les free, si vous comptez sur le fait qu'un free(NULL) ne fera rien, eh bien bonne chance.....
il n'empêche que 3 choses en ressortent, qui sont toujours valables :
1) pour être indépendant de la machine, vaut mieux faire les cast sur des pointeurs (pour mémoire certaines machines (Harris, et Bull) étaient 36 et 42bits...). Rien ne garanti que l'on n'aura pas un des ces jours un tordu de la même manière.
2) pour les sizeof, il est conseillé de le faire sur le type et non sur la variable..
3) et donc la notation que je suis pour les cast n'est pas une absurdité. Peut-être pas ce qui est enseigné de nos jours, certes, mais un maçon, quelque soit la nature du ciment qu'il utilise (précontraint, standard, colle, ciré, etc..) sait toujours faire une maison ;-)
Quelle différence ? Faire un sizeof sur la variable c'est le faire sur le type l'inverse par contre n'est pas vrai.Citation:
2) pour les sizeof, il est conseillé de le faire sur le type et non sur la variable..
On peut savoir d'ou tu tiens ce conseil ? Une référence un exemple parlant concret ?
Le seul exemple que je verrais, c'est le risque de prendre l'habitude de faire sizeof() sur un tableau et tomber ensuite dans le piège en le faisant sur un pointeur.
Problème solvable en C++, mais pas en C.
Pourquoi ? Si le type est pointeur sur objet, à quoi peut bien servir le cast, sachant que malloc() retourne un void * ?Citation:
Envoyé par souviron34
est garanti de fonctionner sur n'importe quelle machine implémentant le langage C. C'est le compilateur qui fait génère le code qui les ajustements nécessaires. Je rappelle que chaque machine a son(ou ses) compilateur(s), même si il a le même nom partout comme gcc ...Code:T *p = malloc(123);
Je ne vois pas du tout pourquoi. Le langage C dit que c'est strictement équivalent, étant donné que la variable a le même type. C'est une question de style et nous sommes nombreux à penser que le style qui facilite la maintenance est préférable. La petite difficulté de lecture du début s'estompe très rapidement...Citation:
2) pour les sizeof, il est conseillé de le faire sur le type et non sur la variable..
Elle a eu sa raison d'être avant l'invention du void (C89), car malloc() retournait (char *), mais s'accrocher à cette vielle lune, même moi qui ait commencé le C et 1988, je ne le fais pas !Citation:
3) et donc la notation que je suis pour les cast n'est pas une absurdité.
Quand j'ai commencé à trainer mes bottes sur news:comp.lang.c dans les années 1999, j'avais 11 ans de C autodidacte derrière moi et je me croyais le roi du monde.
J'ai vite compris que d'autres avaient réfléchi à tout ça de puis bien plus longtemps que moi et proposaient des facilités de codage tout à fait légales et portables. C'est là que j'ai commencé à véritablement apprendre le langage C. D'ailleurs, la fine équipe de c.l.c, sous la responsabilité de Richard Heathfield, éminent contributeur, a fini par pondre un ouvrage tout à fait remarquable : C-Unleashed, qui est sans aucun doute le meilleur livre de C qui existe, puisque écrit par la communauté de haut niveau du langage C, florilège de contributeurs historiques, Ritchie, Stallman, membres du comité de normalisation, utilisateurs éclairés etc. Que du beau monde.
(Je rappelle que clc est un des plus ancien des forums Usenet, et qu'il a été créé à l'époque d'Arpanet, l'ancêtre d'Internet.)
Je fais confiance à la norme et aux implémentations 'dites' conformes (notamment gcc qui est très universel).Citation:
Peut-être pas ce qui est enseigné de nos jours, certes, mais un maçon, quelque soit la nature du ciment qu'il utilise (précontraint, standard, colle, ciré, etc..) sait toujours faire une maison ;-)
Mais il faut savoir débusquer les implémentations non conformes et agir en conséquence. A moins qu'on travaille sur du code 'historique' (legacy code), ça reste des cas très limités.
En qui concerne free(), c'est la norme C90 (extrêmement portable, car la plupart des compilateurs C l'implantent) qui stipule que free() ne fait rien lorsqu'on lui passe NULL. Si ce n'est pas le cas avec les systèmes sur lesquels tu travailles, c'est qu'ils ne sont pas conforme. A part cela, j'ouvrage K&R 2ème édition à l'annexe B5, et je trouve:Citation:
Envoyé par souviron34
Je ne partage pas ton point de vue ni pour les casts, ni pour sizeof. Certes mon expériences est moindre que la tienne, mais je pense qu'il est raisonnable de faire confiance à la norme C90 lorsqu'il s'agit de programmer de manière portable.Citation:
Envoyé par Kernighan & Ritchie
Thierry
Pas de problèmes là.. Je vais me mettre à jour grâce à vous :D je ne suis qu'un vieux crouton... :cry: :cry:Citation:
Envoyé par Emmanuel Delahaye
Dans mon milieu de travail ça a été et la plupart du temps ça reste la norme...Citation:
Mais il faut savoir débusquer les implémentations non conformes et agir en conséquence. A moins qu'on travaille sur du code 'historique' (legacy code), ça reste des cas très limités.
(vous seriez surpris de savoir le nombre de programmes scientifiques (y compris opérationnels) datant d'il y a 15, 20, 25 ou 30 ans : la meilleure des raisons étant qu'ils ont été fait par les utilisateurs et qu'en général ils font ce qu'il doivent faire... Et j'ai même vu récemment (5 ans) le programme de modélisation des vagues dans l'Atlantique, écrit en Fortran77, où la seule modification à apporter était de le passer en Fortran90 (remplacement des fonctions obsolètes) et de le rendre parallèlle (ce qui était le plus long). Mais ce genre de programme, on le re-programme pas....)
et mujigka, en ce qui concerne le free, je suis d'accord, sauf que la deuxième partie de la phrase est beaucoup moins évidente qu'il n'y parait...
rappelez-vous vos expériences passées... ça ne vous dit rien ce genre de bugs ??Citation:
p doit être un pointeur sur un espace mémoire alloué par calloc, malloc ou realloc.
Je n'ai que peu d'expérience, donc cela ne me dit rien. Mais je suis curieux...Citation:
Envoyé par souviron34
Thierry