Bonjour,
Vous pouvez postez ici vos avis, remarques, suggestions sur l'article suivant :
http://rperrot.developpez.com/articles/c/genericite/
NB: Merci de lire ce message avant de poster.
Version imprimable
Bonjour,
Vous pouvez postez ici vos avis, remarques, suggestions sur l'article suivant :
http://rperrot.developpez.com/articles/c/genericite/
NB: Merci de lire ce message avant de poster.
Un super tutorial pour aborder ce point si difficile pour ne pas dire pénible du language C
Merci, ça fait plaisir ;)
Merci pour votre tutoriel, je sens qu'il va m'être très utile :ccool:
Lecture intéressante, bravo et merci.
Je m'étais un peu frotté à la généricité, ou un truc approchant, j'avais trouvé le C assez peu adapté et surtout l'effort coûteux. J'avais décidé de prendre une approche crocolion, par exemple uniquement sur les formats de pixels, en transformant un uint8_t en uint8_t[1].
On demande souvent à un programme écrit en C d'aller vite. Imaginons des fonctions agissant sur des T[n], n connu à l'exécution, ces fonctions intégrant des boucles lourdes (sinon la question de performance n'a pas à être posée). n n'étant pas connu à la compilation, ni le compilateur ni le programmeur ne pourront optimiser en développant les boucles "courtes", par exemple. Si dans la vraie vie, n ne peut prendre que 3 valeurs, 1, 2 et 4, éventuellement une 4eme dans une future version, il sera souvent objectivement plus performant de multiplier les fonctions. Le gros problème, et dans le cas vécu il était réel, c'est que ça casse la centralisation du code. Le préprocesseur peut être une solution. Mais il me semble qu'il est limité, et de toutes façons il me donne des boutons. J'avais préféré utiliser un script (python) pour générer la source C. Ça marche, et même bien, mais il faut dire que j'utilise python au quotidien, que je travaille seul et que j'utilise le plus souvent possible scons. Bon, je m'égare...
J'ai peut-être constaté une imprécision, dans le paragraphe II-B. Je lis "Ainsi, pour notre fonction, ce ne sont pas les variables a et b que nous échangeons mais leur copie". En fait, ce sont des copies des adresses de a et b qui arrivent dans la fonction, et les variables locales correspondantes (paramètres formels ?) qui sont échangées, à toutes fins inutiles.
Egalement, pour la fonctionmême si le lecteur n'est pas censé être débutant, il sera bon d'expliquer (quelques mots, ou deux lignes de code supplémentaires) comment l'appeler. Il me semble qu'il faut créer dans l'appelant des variables pointeur initialisées par les adresses de a et b.Code:void swap( void * d1 , void * d2 ){...}
Rien à voir avec la généricité, mais il y a souvent des incompréhensions dans ce genre de truc. Le statut de l'opérateur adresse et son rapport avec la notion de pointeur sont parfois mal expliqués. Combien de débutants (et même plus) voient &a comme ce qu'il est, rien d'autre qu'une constante immédiate, au même titre que 12L par exemple ?
Bonjour/Bonsoir;
Le tutoriel est très clair et bien structuré, merci pour votre travail.
Cependant je rencontre une difficulté dans la section II-B, je n'arrive pas à comprendre ce code :
La fonction reçoit 2 pointeurs génériques, ça je saisis, la première instruction aussi, mais quand j'arrive à la deuxième je bloque, je ne sais pas ce que ça fait. J'ai déjà vu quelque chose dont la syntaxe est très proche, en l'occurrence : un cast, c'est peut être la même chose, mais même en admettant cette possibilité je n'arrive pas à comprendre.Code:
1
2
3
4
5
6
7 void swap( void * d1 , void * d2 ) { void * tmp; tmp = *(void **)d1; *(void **)d1 = *(void **)d2; *(void **)d2 = tmp; }
Merci de bien détailler.
A+
Le but de la fonction est d'échanger les valeurs pointées par 2 pointeurs génériques passé en paramètre (mais cela, tu l'avais déjà deviné)
Le problème est que l'on ne peut pas déréférencer un pointeur void * et que l'on veut échanger les objets pointés par ces 2 pointeurs.
pour cela, on passe par une "ruse" qui n'est pas très jolie à voie en faisant croire au compilateur que le pointeur void * est un pointeur sur un void *. A ce moment là, on peut déréférencer un pointeur sur un void * puisque l'objet pointé est un void * et plus un void.
La transformation pour indiquer que le void * est en fait un void ** est effectivement un cast. Cela permet d'aider le compilateur (mais pas le lecteur dans ce cas) pour qu'il fasse ce que l'on veut qu'il fasse.
Merci pour ton explication ram-0000. J'y vois plus clair maintenant :ccool: .