ça va pas non plus :cry:
avec les flags on perd l'ordre et je peus avoir plusieurs fois la même task
Version imprimable
Un belle liste chaînée sur des types void* histoire d'avoir une liste chaînée générique qui pour tous types de pointeurs :) comme ça si dans le .h la structure change ça change dans tous le programme enfin je le fairais comme ça perso
Je suis d'accord avec la liste chainée, mais pas sur un void*.
Cela dit, cela commence sérieusement à ressembler à de la programmation objet.
En C++, tu t'en sortirai avec un vector et un operator() dans la classe de tache.
Le void* c'est pour la structure qui gère la liste chaînée.
Ca évite la redondance de code sur la gestion des listes chaînées.
Plus le code est réutilisable mieux c'est et tu évite les chances de prolifération d'un bug con dans tous un programme ^^
par contre, tu dois caster partout, ce qui amène un tas d'autre bugs mal famés
Oui c'est sur mais avec un peu de rigueur ^^
On cherche pas a faire de l'objet puisqu'on est en c, pis le printf c'est en c et on voulait faire un peu pareil :)
c'était pour pas copier coller du code et tout factoriser dans une fonction. On va pas commencer a taper encore plus de code pour géré une liste et tout ça sinon autant taper comme j'ai fait dans mon post d'avant :calim2:. Un nombre variable de paramètre c'est un peu comme une liste chainé sauf qu'on a pas a la gérer.
Après c'était pour savoir si on pouvait pas passer d'argument mais pas en passer ça complique plus alors on part sur une liste de paramètres terminé par un NULL.
Je repasserait ici pour vous dire si ça a marché ou si ça a compliqué le projet :)
Encore un tout grand merci à tout le monde.:ccool:
Quand tu évolue dans le C tu utilise beaucoup de liste chaînée et de structure, ce n'est pas de l'objet même si ça y ressemble un peu, mais tu en es très loin.
L'avantage d'une liste chaînée est que tu as un groupe de donnée de taille dynamique sans réel bidouillage, c'est beaucoup plus propre que du realloc sur un tableau.
En plus tu boucle sur ta liste ce qui te permet d'avoir une exécution générique sur les éléments.
Maintenant les varargs c'est intéressant mais fait attention au limite de ce système.
Et tu peux ne pas passer d'argument tu as juste a mettre NULL et a le vérifier en début de fonction.
mon soucis c'est de factoriser du code pas de le dévellopper ^^
si je dois passer de
àCode:
1
2
3
4
5
6 initialisation(); doTask(Tasks[bidule1]); doTask(Tasks[bidule8]); doTask(Tasks[bidule13]); finalisation();
ça m'avance pas beaucoup parce que ça factorise rien et que ça rajoute des lignes en plus. C'est quand même plus simple d'avoir qu'un appelle de fonctionCode:
1
2
3
4
5
6
7
8
9 list=NULL; list=ajouter(list,tasks[Bidule1]); list=ajouter(list,tasks[Bidule8]); list=ajouter(list,tasks[Bidule13]); intialisation(); doTasklist(list); finalisation(); liberer(list);
à partir du moment que je peux mettre autant de tasks que je veux, c'est carrément plus lisble aussi meme si ça me fait une fonction doTasks compliquée.Code:
1
2 doTasks(tasks[bidule1],tasks[bidule8],tasks[bidule13],NULL);
Ou bien y a un truc qui m'échappe ?:oops:
Si ton code n'est pas agréable à manipuler, c'est qu'il représente mal ses données.
Est-ce que vos pointeurs explicite sont la bonne solution?
Pourquoi êtes-vous obliger d'avoir des initialisations libérations à chaque lot de taches, mais pas à chaque exécution de tache?
Si c'est "ouverture de fichier", "écrire truc", "écrire machin", "fermer fichier", par exemple, c'est normal d'avoir une explicitation.
Essayez d'avoir une structure de type "script", qui n'est autre qu'un ensemble de tache (une liste chainée?)
Ce qui permet de n'avoir qu'une seule fonction, en effet.
Autre possibilité, utiliser des pointeurs de fonctions.
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 typedef void (*action_t) (void); void executer_script(action_t action) { initialisation(); action(); finalisation(); } void alpha(void) { doTask(Tasks[bidule1]); doTask(Tasks[bidule8]); doTask(Tasks[bidule13]); } void beta(void) { doTask(Tasks[bidule3]); doTask(Tasks[bidule7]); } int main() { executer_script(alpha); executer_script(beta); return 0; }
Il est agréable à manipuler avec les fonctions variadiques (lol je me met au jargon :P).
Je trouvais que ça serait plus beau d'avoir pu pas passer de paramètres du tout mais comme c'est pas trop possible je m'en passe. C'était que ça ma question au départ.
Là on est qu'à la conception alors on espère ne pas faire trop de mauvais choix 8O et c'est pour valider nos choix qu'on fait des mini prototypes pour voir si ça passe ou pas. Alors on sait pas si c'est LA bonne solution :koi: mais c'est notre solution qu'on essaye de valider pas à pas. C'est qu'on essaye de dire pourquoi on fait les choix et pourquoi on a pas fait d'autres :mur:.Citation:
Est-ce que vos pointeurs explicite sont la bonne solution?
Pourquoi êtes-vous obliger d'avoir des initialisations libérations à chaque lot de taches, mais pas à chaque exécution de tache?
Si c'est "ouverture de fichier", "écrire truc", "écrire machin", "fermer fichier", par exemple, c'est normal d'avoir une explicitation.
L'initialisation et la finalisation c'est pour du log et puis pour communiquer avec un autre process celui à qui c'est qu'on va donner les taches à faire et qui nous dit en finalisation ce qui a été fait ou pas.
Un autre process nous a donné les taches faisables et la fonctions variadique c'est pour créer les scripts.
C'est un peu ce qu'on fait sauf qu'on a écarté cette solution parce que ça nous créer plein de fonctions et qu'il fallait trouver des noms explicite puis on a trouvé que c'était lisible et compréhensible d'enchainer les tasks à partir du moment qu'on utilise des enum ou des constantes pour les index. Pour l'instant on a 42 chainages possibles et seul 3 qui font quelque chose apparaissent en double sur les 42. Ca aurait voulu dire 42 noms de fonctions à trouver alors que c'est plus lisible directement de lire les taches qui sont faites et que sur les 42 y en a 39 qui sont appelé qu'une fois. Pour les chainage vides on en a que presque 10 mais on les compte pas parce que en modifier un n'impacte pas les autres. C'est pareil pour créer des listes toutes faites, il faut des noms et pis si le nom c'est que le nom des taches c'est pas mieux au final.Citation:
Essayez d'avoir une structure de type "script", qui n'est autre qu'un ensemble de tache (une liste chainée?)
Ce qui permet de n'avoir qu'une seule fonction, en effet.
Autre possibilité, utiliser des pointeurs de fonctions.
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 typedef void (*action_t) (void); void executer_script(action_t action) { initialisation(); action(); finalisation(); } void alpha(void) { doTask(Tasks[bidule1]); doTask(Tasks[bidule8]); doTask(Tasks[bidule13]); } void beta(void) { doTask(Tasks[bidule3]); doTask(Tasks[bidule7]); } int main() { executer_script(alpha); executer_script(beta); return 0; }
L'inconvénients qu'on a trouvé c'est que ça fait 6 endroits où si on modifie il ne faut pas oublier de modifier ailleurs, alors on a commenté ça évidemment. Mais du coup on s'est dit que c'est pas pire qu'un printf avec des formats et que le format doit être modifié à 6 endroits. C'est chiant mais on pense que ça reste gérable.:lol:
Mais peut être aussi qu'on a pas pensé a tout ou correctement :calim2: mais j'espère pas lol
En tout cas c'est super votre implication je ids un gros merci:ccool:
Si une chaine d'opération à un sens, le nom de la fonction est normalement simple à trouver.
Pour la conception, utilisez du français, et pour chaque nom qui se répète dans le texte, envisagés un typedef (structure, énumération ou type simple).
Pour chaque verbe conjugé dont le sujet ou un complément d'objet est l'un de ces noms, il devrait y avoir une fonction.
"initialisation", "finalisation" ne sont pas de bons noms, parce qu'ils ne sont pas discriminant.
ouvertureTransaction, fermetureTransaction serait déjà meilleurs.
Les prototypes ne sont pas suffisant pour la validation d'une architecture.
Idéalement, il faut que vous puissiez expliquer toute l'architecture sans montrer de code.
N'hésite pas à nous en parler plus longuement, nous pouvons vous aider.
Quel est l'intéret immédiat d'avoir un nom de fonction qui décrit les actions du corps sachant qu'on utilise des noms clairs pour les paramètres de la fonction variadique ?
sachant aussi qu'y en a 42 et que sur les 42 39 ne sont utilisé que une fois ?
ça serait quoi l'avantage d'avoir
par rapport àCode:
1
2
3
4
5
6
7
8
9 void script_bidule_1_bidule_8_bidule_13() { doTask(Tasks[bidule_1]); doTask(Tasks[bidule_8]); doTask(Tasks[bidule_13]); } .... executer_script(script_bidule_1_bidule_8_bidule_13);
?Code:doTasks(Tasks[bidule_1], Tasks[bidule_8], Tasks[bidule_13], END_OF_TASKS);
Parceque si y a un avantage clair on prend.
J'avoue que c'est de la fégnantise pendant la phase prototypage. On fera des efforts :mrgreen: à l'implantation. C'est ptêt le mot prototypage qui va pas, c'est plus le test pratique des idées qu'on a qu'un vrai prototypage avec des sketchs et tt ça :oops:Citation:
Pour la conception, utilisez du français, et pour chaque nom qui se répète dans le texte, envisagés un typedef (structure, énumération ou type simple).
Pour chaque verbe conjugé dont le sujet ou un complément d'objet est l'un de ces noms, il devrait y avoir une fonction.
"initialisation", "finalisation" ne sont pas de bons noms, parce qu'ils ne sont pas discriminant.
ouvertureTransaction, fermetureTransaction serait déjà meilleurs.
Naaan c'est clair mais on teste pour être au minimum un peu certains qu'on part pas sur des trucs impossibles (style on prévoit un truc imfaisable 8O et on est djoke pour refaire l'analyse !:marteau:) pis pour pouvoir donner des arguments sur pourquoi on a fait ça plutôt qu'autre chose. Comme pas écrire plein de fonctions avec un nom clair mais qui sont appellé souvent qu'une fois mais choisir d'utiliser une fonction avec des paramètres clairs a la place. Utiliser une fonction variadique plutot que plusieurs versions d'une fonction (genre fonc0(), fonc1(param1), fonc2(param1,param2), ... foncn avec n param) pour conserver une unicité de style et de lecture etc...Citation:
Les prototypes ne sont pas suffisant pour la validation d'une architecture.
Idéalement, il faut que vous puissiez expliquer toute l'architecture sans montrer de code.
N'hésite pas à nous en parler plus longuement, nous pouvons vous aider.
Dire on est fainéant pour la conception on fera mieux au l'implementation est une très mauvaise approche c'est comme dire je ferai les commentaire que j'aurai fini de coder.
Le pb est que ça ne sera jamais fait en plus tout le monde connais la conception mais n’implémentera pas tout, donc vous vous engager a que le reste de votre équipe perde la connaissance au niveau de votre implémentation.
Ce n'est pas professionnel et très dangereux car de mauvaise habitude arrive vite.
La conception et la pour mettre l'architecture et le nommage en place, l'implémentation ce limite au corps.
Ensuite l’intérêt d'avoir des noms clairs c'est d'avoir un code maintenable certes tu es encore en étude et ton projet sera jeté mais les bon reflex ce prenne maintenant.
Le code n'est rien, c'est la conception qui importe le jour ou tu sera en entreprise tu te prendra des porte avec une approche comme celle ci.
La conception te permet de moins reflechir durant l'implémentation afin de te concentrés sur les traitements qui sont plus ou moins mis en place pendant la conception.
Avoir une fonction qui fait le café c'est très mauvais aussi parfois faire "beaucoup de code" te permet juste d'avoir un code souple efficace propre et facile a implémenter.
Ce n'est pas méchant loin de la, c'est un conseil que je te donne pour que tu puisse mener a bien tes missions, le travail d'équipe est un exercice difficile qui ne faut surtout pas prendre à la légère et plus tard tu sera amené a faire un code que tu ne maintiendra peu être pas c'est pour cela que ces phases sont très importantes.
Bonne journée
Bonjour,
J'en réfère souvent à Boileau:
Ce que je traduis personnellement par:Citation:
Envoyé par Boileau
Rien n'est strictement impossible en C (tant qu'on reste dans la manipulation du PC…), surtout dans les projets scolaires.Citation:
"Ce qui se conçoit bien s'explique clairement, et le code pour le réaliser vient facilement".
De mon expérience personnelle, j'ai retenu une chose essentielle: un programme ne fait que manipuler des données.
On peut les représenter comme on veut, mais certains choix rendent toutes les manipulations triviales.
Il ne faut pas hésiter à écrire des types.
Puisqu'un programme résoud un problème, je considère que sa conception est terminée quand en montrant la liste des types manipulés, n'importe qui voit comment résoudre le dit problème.
Bon d'accord, s'il a aussi les algorithmes théoriques.
La conception est la clé du développement. Bien faite, elle rend le développement plus rapide, plus sûr, plus simple.
Bref, la conception est quasiment toute l'histoire. :mrgreen:
Je suis d'accord avec toi :D heureusement c'est pas du tout ce que j'ai dit ouf
Je trouve pas qu'on est est fainéant puisque on valide tot notre conception. On a pondu des modèles, on vérifit que c'est implantable, on compare les implantations et on argumente sur le choix du pourquoi avoir choisit un plutot que l'autre.Citation:
J'avoue que c'est de la fégnantise pendant la phase prototypage. On fera des efforts à l'implantation. C'est ptêt le mot prototypage qui va pas, c'est plus le test pratique des idées qu'on a qu'un vrai prototypage avec des sketchs et tt ça
Bonne journée à toi aussi :-o