Methode et beauté du code

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
Backup
Messages : 14526
Inscription : lun. 26/avr./2004 0:40

Methode et beauté du code

Message par Backup »

lorsque je code , j'utilise quasiment tout le temps ce type d'architecture :


***************
Structures
initialisation des variables
Declaration des Procedures

*****************
Creation de l'interface utilisateur (hors procedure )
************************
Boucle principale (Events )

***********************
Zone des procedures
************************
DataSection
************************
-----------------------------------------------------------------------------------------------------------
les procedures toujours en fin de code !
cela evite d'avoir a parcourir 3 plombe un code pour arriver a la boucle principale ....
je considere les procedures comme des "accessoire" au programme ... donc il vont a la fin
l'appel se faisant la plupart du temp dans la boucle principale

pour ce qui concerne l'ecriture des variables :
pour les flags, j'utilise toujours le mot "flag_" en debut de nom d'un Flag

je Type en permanence toutes mes variables , comme ça si au milieu d'un code, je vois toto.l , je connais son type
et ceux meme si Purebasic permet de typer une seule fois en debut de code une variable, je garde le type affiché
tout au long du code :)

j'ajoute qu'il m'arrive d'utiliser des variables "Poubelle" , des variables qui ne servent que temporairement et tres localement
dans un code , ces variables, je leur donne un nom qui ne veux rien dire genre "qdfqf.s" ... lorsque je vois ce type de variable , je sais qu'elle me sert que dans les 10 prochaines lignes maximum ...

on peut aussi (mais je ne le fait pas ) ajouter une lettre devant le nom de la variable pour connaitre son type
genre L_toto.s (le "L" signifiant qu'elle est Local )
ou bien G_toto.s (le "G" signifiant qu'elle est Global ) etc ...

je n'utilise quasiment jamais les Includes ... (l'action de séparer un gros programme en plusieurs fichiers)
car .. je me suis rendu compte qu'au moment de debugger un prg fait ainsi , c'etait parfois tres difficile de savoir
ou se trouve un Bug ! ....
l'erreur apparait dans un fichier ... alors qu'en fait elle est généré par un autre fichier ...
comme dirai l'autre "Cherchez l'erreur" :mrgreen:
alors qu'en ayant tout le code dans le meme Editeur ... c’est limpide ... :)
Dernière modification par Backup le lun. 28/avr./2014 9:56, modifié 13 fois.
Patrick88
Messages : 1564
Inscription : mer. 21/janv./2004 18:24

Message par Patrick88 »

avant de faire du basic, je suis passé par la case Pascal en autodidacte sur cpc6128 (je savais meme pas faire une boucle for/next à l'époque...) :wink:

pis un collègue lâsser de mes réparties moqueuse m'a assené un grand coup de "la bible de turbo pascal" sur le sommet de la tête...

et depuis bizarrement quel que soit le langage,

constante
type
enregistrement
variable globale
déclare (s'il y a lieu)(très rarement en fait)
fonction (procedure qui renvoie un argument)
procedure

init
programme principal
fin

:wink: :lol: :roll:

pat
cha0s
Messages : 681
Inscription : sam. 05/mars/2005 16:09

Message par cha0s »

comme je l'ai dit dans l'autre post ta structure ne marche pas dobro

Code : Tout sélectionner

Declare test(*chose.test)

Structure test
  test.s
EndStructure

Procedure test(*chose.test)

EndProcedure
L'IDE de pure me renvoie une erreur car il faut déclarer les structure avant.

sur Chronos le precompilateur génère un code comme ceci :

Code : Tout sélectionner

;===========================================================;
;
; Main File : main.pb
; Code generated by chronos
;
;===========================================================;

EnableExplicit

IncludeFile "Constant.pbi"    ;constante
IncludeFile "Structure.pbi"    ;structure
IncludeFile "Global.pbi"        ;variables globales
IncludeFile "Declaration.pb" ;déclaration des procédures
IncludeFile "Procedure.pb"   ;Procédure et macro

repeat


forever

;data 
Sinon je vous conseille EnableExplicit qui vous obligera a déclarer chaque variable ce qui évite les erreurs.
Anonyme2
Messages : 3518
Inscription : jeu. 22/janv./2004 14:31
Localisation : Sourans

Message par Anonyme2 »

Je suis 90% d'accord avec Patrick88, les 10% c'est parce que je ne sais pas à quoi correspond la zone enregistrement.

Je met toujours toujours les procedures avant d'écrire le code de la boucle.

Je rajoute que je met la datasection complètement à la fin.

J'ai pris l'habitude de commenter presque chaque ligne de code, ça ne prend que peut de temps et c'est pratique si on revient dessus plusieurs mois plus tard. Lorsqu'un truc me parait important , j'ajoute des lignes de commentaire pour expliquer.

aujourd'hui j'évite d'imbriquer des if dans des if dans des if dans des if ... car sur de grands codes, on s'y perd et si une erreur intervient, c'est pas toujours simple à retrouver.

Je vous met une procedure extraite du code sur lequel je travaille, beaucoup de tests et de procedureReturn, mais c'est simple, clair et ça marche bien.

Je ne dis pas que c'est la meilleure manière mais elle me convient et a l'avantage à mes yeux de clarifier le code.

J'utilise un décalage de 5 espaces, ça améliore la lecture.

Code : Tout sélectionner

Procedure.i IS_Format_NE(hModule)
     
     ;///////////////////////////////////////////////////////////////////////////////////////////////////
     ;//
     ;// FONCTION: IS_Format_NE()
     ;// 
     ;// BUT: tester une partie du header du fichier en mémoire pour déterminer si ce fichier
     ;//      est un fichier 16 bits (format NE  - Windows 3.x)
     ;//
     ;// PARAMS: hModule - pointeur sur le premier octet de la mémoire allouée pour charger le fichier icl
     ;//
     ;// RETOURNE: #True si le fichier est au format NE
     ;//           #Return_Error (= #Fasle) si le fichier n'est pas au format NE
     ;//
     ;// UTILISATION : Typiquement, on l'utilise immédiatement après avoir chargé le fichier en mémoire
     ;//               Plusieurs fonctions utilisent une partie de ce code mais sans en faire les tests car
     ;//               ils ont été faits dans cette procedure
     ;//               
     ;///////////////////////////////////////////////////////////////////////////////////////////////////
     
     
     
     ;// mémorise l'adresse du contenu de la ressource, à partir du début du fichier modifié dans chaque boucle
     Protected *Memory_Add_temp
     ;// memorise la dernière adresse valide du fichier en mémoire pour vérifier le non dépassement
     Protected *LastMemoryAdress
     ;// mémorise l'offset de la zone NE depuis le début du fichier (pas l'adresse, l'offset depuis le début du fichier)
     Protected Offset_NE_Header
     ;// mémorise l'offset de la Resource Table (pas l'adresse, l'offset depuis le début du fichier)
     Protected Offset__Resource_Table
     ;// mémorise le coefficient de mutiplication de l'offset permettant de multiplier les valeurs virtuelles pour obtenir les valeurs réeelles
     Protected rscAlignShift
     
     
     
     ;// on teste si le pointeur est nul, on stoppe si null
     If hModule = #Null
          SetError_Code(#Error_Code_Pointeur_Null)
          ProcedureReturn #Return_Error
     EndIf
     
     ;// mémorise la valeur du pointeur, ce pointeur va évoluer
     *Memory_Add_temp = hModule
     
     ;// teste la taille de la mémoire qui doit valoir au moins 2 octets pour lire #IMAGE_DOS_SIGNATURE
     If MemorySize(*Memory_Add_temp)<SizeOf(word)
          SetError_Code(#Error_Code_Reading_Over_LastMemoryFileAdress)
          ProcedureReturn #Return_Error
     EndIf
     
     ;// on avance le pointeur sur la zone d'énumération après avoir testé le header
     ;// Lecture et vérification de la signature MS-DOS du fichier, "MZ"
     If UPeekW(*Memory_Add_temp)<>#IMAGE_DOS_SIGNATURE
          SetError_Code(#Error_Code_IMAGE_DOS_SIGNATURE)
          ProcedureReturn #Return_Error
     EndIf
     
     ;// définition de la dernière adresse de la mémoire, ne pas écrire après !
     *LastMemoryAdress = *Memory_Add_temp + MemorySize(*Memory_Add_temp)-1
     
     ;// vérifie que les adresses de la zone IMAGE_DOS_HEADER sont définies
     If (*Memory_Add_temp + SizeOf(IMAGE_DOS_HEADER))>*LastMemoryAdress
          SetError_Code(#Error_Code_Reading_Over_LastMemoryFileAdress)
          ProcedureReturn #Return_Error
     EndIf
     
     ;// lecture de l'offset du NE header
     Offset_NE_Header = PeekL(*Memory_Add_temp + OffsetOf(IMAGE_DOS_HEADER\e_lfanew))
     
     ;// teste que l'offset est différent de 0 sinon erreur
     If Offset_NE_Header = 0
          SetError_Code(#Error_Code_OFFSET_NULL_ICL_NE)
          ProcedureReturn #Return_Error
     EndIf
     
     ;// avance le pointeur pour arriver sur la zone IMAGE_OS2_HEADER
     ;// cette zone commence à l'adresse de base + la valeur de la variable Offset_NE_Header
     *Memory_Add_temp + Offset_NE_Header
     
     ;// vérifie que les adresses de la zone IMAGE_OS2_HEADER sont définies
     If (*Memory_Add_temp + SizeOf(IMAGE_OS2_HEADER)>*LastMemoryAdress)
          SetError_Code(#Error_Code_Reading_Over_LastMemoryFileAdress)
          ProcedureReturn #Return_Error
     EndIf
     
     ;// vérification de la signature, élément ne_magic.w (Magic number) de la structure IMAGE_OS2_HEADER
     If UPeekW(*Memory_Add_temp)<>#IMAGE_OS2_SIGNATURE
          SetError_Code(#Error_OS2_SIGNATURE)
          ProcedureReturn #Return_Error
     EndIf
     
     ;// lecture de l'offset de la table des ressources
     Offset__Resource_Table = UPeekW(*Memory_Add_temp + OffsetOf(IMAGE_OS2_HEADER\ne_rsrctab))
     
     If Offset__Resource_Table = #Null
          SetError_Code(#Error_Offset__Resource_Table_Null)
          ProcedureReturn #Return_Error
     EndIf
     
     ;// on positionne le pointeur sur la Resource Table
     *Memory_Add_temp + Offset__Resource_Table
     
     ;// vérifie que les adresses de la zone RESOURCE_TABLE sont définies
     If (*Memory_Add_temp + SizeOf(RESOURCE_TABLE)>*LastMemoryAdress) Or (Offset__Resource_Table<1)
          SetError_Code(#Error_Code_Reading_Over_LastMemoryFileAdress)
          ProcedureReturn #Return_Error
     EndIf
     
     ;// Lecture du décalage, élément de la table de ressources
     rscAlignShift = UPeekW(*Memory_Add_temp + OffsetOf(RESOURCE_TABLE\rscAlignShift))
     
     ;// teste que le décalage existe et limite à 1Go la taille possible avec un décalage de 14
     If (rscAlignShift<0) Or (rscAlignShift>14)
          SetError_Code(#Error_RESOURCE_TABLE_rscAlignShift)
          ProcedureReturn #Return_Error
     EndIf
     
     ProcedureReturn #True
EndProcedure
Patrick88
Messages : 1564
Inscription : mer. 21/janv./2004 18:24

Message par Patrick88 »

Denis a écrit :Je suis 90% d'accord avec Patrick88, les 10% c'est parce que je ne sais pas à quoi correspond la zone enregistrement.
en fait, en pascal c'est dans la zone

Code : Tout sélectionner

TYPE
 T_mon_enregistrement = record
   ...
 end;
je mélange un peu tout les langages à force...

dure de respecter cette structuration du code avec le LISP par exemple :D

pat
Backup
Messages : 14526
Inscription : lun. 26/avr./2004 0:40

Message par Backup »

cha0s a écrit :comme je l'ai dit dans l'autre post ta structure ne marche pas dobro
Merci j'ai modifié !!

c'est bon a savoir !! :)
Avatar de l’utilisateur
case
Messages : 1527
Inscription : lun. 10/sept./2007 11:13

Message par case »

personellement je construit toujours mon code avec les procedures a la fin, je trouves cela plus clair.

en gros

1/ structures
2/ initialisaton des variables
3/declaration procedures
4/boucle principale
5/procedures
6/data


je commente mon code, je met noir de commentaires a droite des lignes de code

je balise mon code

je met encore des commentaires sur le fonctionnement du code

j'explique a quoi servent les variables


par exemple :

Code : Tout sélectionner

Global NewList canaux.canal()                      ; garde les canaux disponibles 
en pb j'abuse des balisage de type

Code : Tout sélectionner

;- procedures 
en mettant un ;- le commentaire deviens visible dans l'explorateur de l'ide dans les procedures un simple clic et je retrouve la bonne section du code

Code : Tout sélectionner

;- structure
-
-
-
;- gloabales
-
-
-
;- declaration procedures
-
-
-
-
-
;-boucle principale
-
-
-
-
;-procedures
-
-
-
;-datas
-
-
-
-

ImageImage
Backup
Messages : 14526
Inscription : lun. 26/avr./2004 0:40

Message par Backup »

a force de temoignage on va pouvoir avoir un chemin a suivre pour les débutants en Purebasic :)
Avatar de l’utilisateur
flaith
Messages : 1487
Inscription : jeu. 07/avr./2005 1:06
Localisation : Rennes
Contact :

Message par flaith »

Comme Denis, je programme depuis presque 30 ans, j'en ai même fait des études.

Alors je construit toujours mes programmes de la même façon (ou presque car avec l'assembleur c'est pas pareil) :

Je décomposes par type (les constantes, globales, Structures, DataSection, puis les procédures), puis le programme principal fait les includes de toute ce petit monde.

Bien sur c'est pour le cas ou le projet est important, pour un petit programmes, les déclarations, les constantes, les procédures, la boucle principale et les datasections, c'est une méthode comme une autre, l'important c'est de s'y retrouver, sauf si on veut faire du travail collaboratif et la, je ne le répéterais jamais assez : "commentez le plus possible ce que vous faites dans vos procédures" :wink:
Dernière modification par flaith le mer. 28/janv./2009 21:43, modifié 2 fois.
Anonyme

Message par Anonyme »

Pareil que case.
Pour les plus gros code ( + de 1000 lignes environs ) je préfère partitionner en plusieurs fichiers.
Le Soldat Inconnu
Messages : 4312
Inscription : mer. 28/janv./2004 20:58
Localisation : Clermont ferrand OU Olsztyn
Contact :

Message par Le Soldat Inconnu »

hum, et bien moi, un comme gnozal, je crois, je préfère la méga source avec tout dedans

mais j'adopte une architecture par fonction

en gros je groupe les globales, list, data et procedure de chaque fonction du programme
et je sépare avec des lignes vierges

un peu comme si j'avais copier coller les includes dans le programmes principal

chacun son truc, moi, je préfère remonter dans le code (surtout avec le pliage de procédure, c'est tres facile) que chercher dans quel fichier j'ai bien pu foutre la fichu fonction que je veux modifier

mon plus gros code fait 7300 lignes, et je m'y retrouve très bien comme ça :)

Mais, il m'arrive d'utiliser des includes, notamment pour les procedures de chargement de fichier (pour les jeux surtout)
parceque c'est volumineux et pas utile quand on code
c'est bien le seul cas pour l'instant.

En gros include pour ce qui sert pratiquement jamais, et tout le reste dans le fichier principal
Je ne suis pas à moitié Polonais mais ma moitié est polonaise ... Vous avez suivi ?

[Intel quad core Q9400 2.66mhz, ATI 4870, 4Go Ram, XP (x86) / 7 (x64)]
Anonyme

Message par Anonyme »

oui, mais cela te force à réécrire les mêmes routines par exemple , des routines de maths.
enfin , chacun fait comme il le sent ^^
Le Soldat Inconnu
Messages : 4312
Inscription : mer. 28/janv./2004 20:58
Localisation : Clermont ferrand OU Olsztyn
Contact :

Message par Le Soldat Inconnu »

pour les routines, j'ai une base de données de fonction, et je fais du copier coller des fonction dont j'ai besoin :roll:
Je ne suis pas à moitié Polonais mais ma moitié est polonaise ... Vous avez suivi ?

[Intel quad core Q9400 2.66mhz, ATI 4870, 4Go Ram, XP (x86) / 7 (x64)]
Ollivier
Messages : 4190
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Message par Ollivier »

Moi c'est la technique de l'oignon que l'on épluche couche après couche...
C'est toujours agréable un programme plié

Code : Tout sélectionner

{ En-tête }

Main()
Ou la technique du champignon. Le code est immangeable puisqu'il est généré par d'autres codes. Avec ça, c'est le dicton "Quand on veut, on peut"

Ou enfin la technique du ni vu ni connu. Macros à bloc.

Conclusion: Entre les oignons, les champignons et les maquereaux, il y a le choix du menu.
Avatar de l’utilisateur
venom
Messages : 3071
Inscription : jeu. 29/juil./2004 16:33
Localisation : Klyntar
Contact :

Message par venom »

Pour parler du sujet,
c'est vrai que d'instaurer une norme pour le codage parementerai de gagner énormément de temps.

mais comme je viens de lire dans les posts précédents, "les vieux" ont et garderont leurs habitudes. ( j'ai mis entre guillemet :wink: )
donc il y aura toujours conflits. :?

exemple moi j'évite les procédures tant que je peut.
mais bon sa serai tellement plus compréhensible ainsi.





@++
Windows 10 x64, PureBasic 5.73 x86 & x64
GPU : radeon HD6370M, CPU : p6200 2.13Ghz
Répondre