Page 1 sur 1

[TUTO] Utiliser les flags

Publié : jeu. 22/déc./2016 18:50
par microdevweb
Bonjour à tous,

Les flags (drapeaux, en français) sont largement utilisés par les fonctions de PureBASIC, par exemple avec OpenWindow() pour centrer une fenêtre et en même temps la mettre en plein écran. Ils permettent donc de spécifier certaines propriétés en n'utilisant qu'une seule variable.
Mais comment cela fonctionne-t-il ?
  • Un flag peut avoir pour valeur 0 ou 1.
  • Un entier long (.l) est codé sur 4 octets, soit 32 bits
Nous avons donc 32 bits que nous allons pouvoir mettre à 0 ou à 1, soit 32 flags.

Pour arriver à cela, il va cependant falloir respecter quelques règles.
  • La valeur de nos constantes doit être codée sur un seul bit des 32 bits.
  • Il faudra veiller à ne pas écraser la valeur de la variable, on ne pourra donc pas utiliser l'affectation =
1) Comment sont codés nos nombres ?
Nous pensons en base 2. On démarre du bit de poids faible 0 jusqu'au bit de poids fort 31. En décimal cela donne :

Code : Tout sélectionner

#Flag_0 = 1   ; = %1 en binaire (bit 0 fixé)
#Flag_1 = 2   ; = %10 (bit 1)
#Flag_2 = 4   ; = %100 (bit 2)
#Flag_3 = 8   ; = %1000 (bit 3)
#Flag_4 = 16  ; = %10000 (bit 4)
#Flag_5 = 32  ; = %100000 (bit 5)
#Flag_6 = 64  ; = %1000000 (bit 6) 
#Flag_7 = 128 ; = %10000000 (bit 7)
#Flag_8 = 256 ; = %100000000 (bit 8)
; Etc...
Un manière plus simple est de le faire en hexadécimal, $1, $2, $4, $8 par 4 octets

Code : Tout sélectionner

#Flag_0 = $0001 (bit 0 fixé)
#Flag_1 = $0002 (bit 1)
#Flag_2 = $0004 (bit 2)
#Flag_3 = $0008 (bit 3)
#Flag_4 = $0010 (bit 4)
#Flag_5 = $0020 (bit 5)
#Flag_6 = $0040 (bit 6)
#Flag_7 = $0080 (bit 7)
#Flag_8 = $0100 (bit 8)
; etc...
Ou en utilisant une énumération binaire

Code : Tout sélectionner

EnumerationBinary
    #Flags1 ; égale à 1
    #Flags2 ; égale à 2
    #Flags3 ; égale à 4
    #Flags4 ; égale à 8
    #Flags5 ; égale à 16
  EndEnumeration
2) Mettre une ou plusieurs valeurs, sans écraser les autres, par exemple pour passer vos flags à une fonction, se fait avec le OU logique (OR), opérateur "|" en PB.

Code : Tout sélectionner

mesFlags = #Flag_0 | #Flag_6 ;(= %01000001 en binaire ou $0041 en hexa ou 65 en décimal)
Le OU logique se comprend avec une table de vérité.
Exemple avec 2 valeurs :

Code : Tout sélectionner

A   B  SORTIE
0 | 0 -> 0
0 | 1 -> 1
1 | 0 -> 1
1 | 1 -> 1
Cet opérateur permet donc de ne modifier qu'un bit à la fois, sans altérer les autres.

3) Lire un flag, c'est à dire lire la valeur d'un bit spécifique.
Pour ce faire nous allons utiliser le ET logique (AND), opérateur "&" en PB. Voici sa table de vérité :

Code : Tout sélectionner

A   B  SORTIE
0 & 0 -> 0
0 & 1 -> 0
1 & 0 -> 0
1 & 1 -> 1
La sortie n'est à 1 que si les deux entrées sont à 1.
Exemple :

Code : Tout sélectionner

mesFlags = #Flag_0 | #Flag_6
If mesFlags & #Flag_6
    Debug "Le bit 6 est à 1"
EndIf
If mesFlags & #Flag_3
    Debug "Le bit 3 est à 1"
Else
    Debug "Le bit 3 est à 0"
EndIf
Et si on veux maintenant modifié l'état d'un flags et le placer à 0, comment faire?

Pour cela nous allons utiliser l'opérateur AND (&) ainsi que l'opérateur NOT (~) comme ceci

Code : Tout sélectionner

mesFlags =mesFlags &~#Flags3
L'opérateur not va inversé tous les bits

Code : Tout sélectionner

0000 0000 0010 0000 ; #Flag5 (32 en décimal) 
1111 1111 1101 1111 ;devient après le NOT
Donc tous les bits à 1 seront simplement copiés avec l'opérateur ET le bit à 0 sera quant à lui mit à 0.

Exemple complet:

Code : Tout sélectionner

EnumerationBinary
    #Flags0 ; égale à 1
    #Flags1 ; égale à 2
    #Flags2 ; égale à 4
    #Flags3 ; égale à 8
     #Flags4 ; égale à 16
    #Flags5 ; égale à .32
    #Flags6 ;égale à 64
    #Flags7 ;égale à 128
EndEnumeration
Global mesFlags .l
Procedure Lit()
    For i=0 To 7
        p.l=Pow(2,i)
        If(mesFlags &p)
            Debug "Le flags "+Str(i)+" est à 1"
        Else
            Debug "Le flags "+Str(i)+" est à 0"
        EndIf
    Next
EndProcedure
; Ici j'active le Flag 1,3 et 5
mesFlags =#Flags1|#Flags3|#Flags5

; Lecture des flags pour voir le résultat
Lit()

; ici je vai placer le flag 3 à 0

mesFlags =mesFlags &~#Flags3

; Lecture des flags pour voir le résultat
Lit()

Voila, j'espère que ce petit tuto vous sera utile.

Merci à majikeyric et djes pour leurs remarques et corrections :wink:

Re: [TUTO] passé jusqu'à 32 flag avec une seule variable

Publié : jeu. 22/déc./2016 23:25
par majikeyric
... pauvre tache

Re: [TUTO] passé jusqu'à 32 flag avec une seule variable

Publié : ven. 23/déc./2016 0:34
par Zorro
passé jusqu'à 32 flag
super_variable.s ="a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,0,1,2,3,4,5,6,7,8,9,riri,fifi,loulou,et, autant,de,flag,que,tu,veux,dans,une,seule,variable,c'est ,étonnant,non,?"

54 flag dans ma super_variable ! ;) :mrgreen:

et ici : variable.i <<< 8 octets (avec compilateur 64-bit) -9223372036854775808 à +9223372036854775807 , ça en fait des flags ...


je veux dire, les flag c'est une petite memoire, qui permet de noter un evenement dans le prg ,qui resservira plus tard ...
a partir de là , pourquoi se bloquer sur du binaire ?

dans le cadre de la programmation sur Microprocesseur ...(assembleur ) ça peut s'envisager
mais en Purebasic .... franchement, je vois pas trop l’intérêt ...

Mais merci pour le tuto .. :)

Re: [TUTO] passé jusqu'à 32 flag avec une seule variable

Publié : ven. 23/déc./2016 1:17
par microdevweb
Merci majikeyric, pour l'astuce de l’énumération binaire;

Zorro, il m'arrive souvent dans mes procédures d'utiliser des flag et les fonctions de Purebasic aussi d’ailleurs maintenant libre à chaque personne d'en voir un intérêt ou pas :wink: .

Re: [TUTO] passé jusqu'à 32 flag avec une seule variable

Publié : ven. 23/déc./2016 8:38
par Micoute
Zorro a écrit :pourquoi se bloquer sur du binaire ?
Parce que c'est la seule langue que comprend le multiprocesseur et en plus on n'est absolument pas limité au binaire, les langages de haut niveau tel que PureBasic ont été créés pour ça

Merci microdevweb, j'apprécie ton tuto.

Re: [TUTO] passé jusqu'à 32 flag avec une seule variable

Publié : ven. 23/déc./2016 11:46
par djes
Je t'ai corrigé tes fautes et aussi quelques erreurs. Il y a une faute aussi dans le titre, moi je mettrais plutôt "Utiliser les flags". Tu corriges si tu veux ;)

Code : Tout sélectionner

Bonjour à tous,

Les flags (drapeaux, en français) sont largement utilisés par les fonctions de PureBASIC, par exemple avec OpenWindow() pour centrer une fenêtre et en même temps la mettre en plein écran. Ils permettent donc de spécifier certaines propriétés en n'utilisant qu'une seule variable. 
Mais comment cela fonctionne-t-il ?
[list]
[*]Un flag peut avoir pour valeur 0 ou 1.
[*]Un entier long (.l) est codé sur 4 octets, soit 32 bits[/list]

Nous avons donc 32 bits que nous allons pouvoir mettre à 0 ou à 1, soit 32 flags.

Pour arriver à cela, il va cependant falloir respecter quelques règles.
[list]
[*] La valeur de nos constantes doit être codée sur un seul bit des 32 bits.
[*] Il faudra veiller à ne pas écraser la valeur de la variable, on ne pourra donc pas utiliser l'affectation =[/list]

1) Comment sont codés nos nombres ?
Nous pensons en base 2. On démarre du bit de poids faible 0 jusqu'au bit de poids fort 31. En décimal cela donne :
[code]
#Flag_0 = 1   ; = %1 en binaire (bit 0 fixé)
#Flag_1 = 2   ; = %10 (bit 1)
#Flag_2 = 4   ; = %100 (bit 2)
#Flag_3 = 8   ; = %1000 (bit 3)
#Flag_4 = 16  ; = %10000 (bit 4)
#Flag_5 = 32  ; = %100000 (bit 5)
#Flag_6 = 64  ; = %1000000 (bit 6) 
#Flag_7 = 128 ; = %10000000 (bit 7)
#Flag_8 = 256 ; = %100000000 (bit 8)
; Etc...
Un manière plus simple est de le faire en hexadécimal, $1, $2, $4, $8 par 4 octets

Code : Tout sélectionner

#Flag_0 = $0001 (bit 0 fixé)
#Flag_1 = $0002 (bit 1)
#Flag_2 = $0004 (bit 2)
#Flag_3 = $0008 (bit 3)
#Flag_4 = $0010 (bit 4)
#Flag_5 = $0020 (bit 5)
#Flag_6 = $0040 (bit 6)
#Flag_7 = $0080 (bit 7)
#Flag_8 = $0100 (bit 8)
; etc...
2) Mettre une ou plusieurs valeurs, sans écraser les autres, par exemple pour passer vos flags à une fonction, se fait avec le OU logique (OR), opérateur "|" en PB.

Code : Tout sélectionner

mesFlags = #Flag_0 | #Flag_6 ;(= %01000001 en binaire ou $0041 en hexa ou 65 en décimal)
Le OU logique se comprend avec une table de vérité.
Exemple avec 2 valeurs :

Code : Tout sélectionner

A   B  SORTIE
0 | 0 -> 0
0 | 1 -> 1
1 | 0 -> 1
1 | 1 -> 1
Cet opérateur permet donc de ne modifier qu'un bit à la fois, sans altérer les autres.

3) Lire un flag, c'est à dire lire la valeur d'un bit spécifique.
Pour ce faire nous allons utiliser le ET logique (AND), opérateur "&" en PB. Voici sa table de vérité :

Code : Tout sélectionner

A   B  SORTIE
0 | 0 -> 0
0 | 1 -> 0
1 | 0 -> 0
1 | 1 -> 1
La sortie n'est à 1 que si les deux entrées sont à 1.
Exemple :

Code : Tout sélectionner

mesFlags = #Flag_0 | #Flag_6
If mesFlags & #Flag_6
    Debug "Le bit 6 est à 1"
EndIf
If mesFlags & #Flag_3
    Debug "Le bit 3 est à 1"
Else
    Debug "Le bit 3 est à 0"
EndIf
Voila, j'espère que ce petit tuto vous sera utile.[/code]

Re: [TUTO] Utiliser les flags

Publié : ven. 23/déc./2016 12:39
par microdevweb
Merci djes
c'est vrai que c'est un peux plus compréhensible

Re: [TUTO] passé jusqu'à 32 flag avec une seule variable

Publié : ven. 23/déc./2016 14:03
par JohnJohnsonSHERMAN
Merci pour ce tuto, bien que je connaissais déja le principe :) Ca a le mérite d'éclaircir certains points, en particulier pour récupérer un flag (je me rapelle jamais comment faire :mrgreen: ) :D

@Dobro : C'est plus dans la "philosophie" de PB de passer les flags avec des constantes numériques (genre "#PB_Window_ScreenCentered | #PB_Window_SystemMenu"), plutôt que de le faire avec une chaine ou autres, et la méthode binaire est tout simplement la mieux adaptée à des flags numériques combinables ;) En plus ca fait "propre" je trouve.

Re: [TUTO] Utiliser les flags

Publié : ven. 23/déc./2016 14:27
par djes
microdevweb a écrit :Merci djes
c'est vrai que c'est un peux plus compréhensible
De rien, le plus dur, c'est de commencer lorsqu'on se retrouve devant une "feuille blanche". Merci à toi !

Re: [TUTO] passé jusqu'à 32 flag avec une seule variable

Publié : ven. 23/déc./2016 15:43
par Zorro
JohnJohnsonSHERMAN a écrit : @Dobro : C'est plus dans la "philosophie" de PB de passer les flags avec des constantes numériques (genre "#PB_Window_ScreenCentered | #PB_Window_SystemMenu"), plutôt que de le faire avec une chaine ou autres, et la méthode binaire est tout simplement la mieux adaptée à des flags numériques combinables ;) En plus ca fait "propre" je trouve.

je ne critique pas l'optimisation de la chose :)
je dis juste que le binaire n'est pas obligatoire

la tu parles toi même de "passage de Flags" ...
en fait il s'agit de parametres , hors ce système permet de diminuer le nombre de parametres ....
mais est limité par l'information (0 ou 1 )
hors un flag peut véhiculer des informations bien plus complexes que 0 ou 1

c'est juste ça que je souligne , et que le Tuto n'aborde pas

prenons un exemple alors ...

Code : Tout sélectionner


Procedure test(Fl.s)
		If stringfield(FL,1,",")="a"
				debug "Fl=a"
		Endif
		;
		If stringfield(FL.s,2,",")="b"
				debug "Fl=b"
		Endif
		If stringfield(FL.s,3,",")="f" ; <<< ne trouvera pas cette valeur qui pourrai allez de a à z , ou l'infini si on utilise des mots et plus de lettres
				debug "Fl=f"
		Else
				debug "pas activé le 3em parametre" ; <<< no limite !!
		Endif
		If stringfield(FL.s,4,",")="super parametre"
				debug "Fl=super parametre"
		Endif
EndProcedure
calldebugger
Flagg.s="a,b,c,super parametre"
test(Flagg.s)


on perd probablement en vitesse , mais on gagne en richesse d'informations (ce qui au final, peut nous avoir fait gagner de la vitesse ) :)

Re: [TUTO] Utiliser les flags

Publié : ven. 23/déc./2016 20:02
par Kwai chang caine
Pour une fois, comme notre "cher man", je connaissais aussi le principe, j'en avais eu besoin dans un de mes codes et SHARDIK, de mémoire, m'avait dépanné 8)
Ce TUTO est génial car tu expliques en détail ce phénomène que je trouve vraiment MAGIQUE 8O
Merci 8)

Re: [TUTO] Utiliser les flags

Publié : sam. 24/déc./2016 12:29
par microdevweb
J'ai ajouté au tuto la manière de procéder pour placer une flags spécifique à 0.

Bonne fête à tous :wink:

Re: [TUTO] Utiliser les flags

Publié : jeu. 15/juin/2017 14:48
par boddhi
Bonjour,

A la lecture de ce tutoriel, je me permets juste de signaler une petite coquille au point 3 du tuto :
3) Lire un flag, c'est à dire lire la valeur d'un bit spécifique.
Pour ce faire nous allons utiliser le ET logique (AND), opérateur "&" en PB. Voici sa table de vérité :

Code : Tout sélectionner

A   B  SORTIE
0 | 0 -> 0
0 | 1 -> 0
1 | 0 -> 0
1 | 1 -> 1
où il faudrait lire :

Code : Tout sélectionner

A   B  SORTIE
0 & 0 -> 0
0 & 1 -> 0
1 & 0 -> 0
1 & 1 -> 1

Cordialement.

Re: [TUTO] Utiliser les flags

Publié : jeu. 15/juin/2017 15:28
par Zorro
exacte !! :)

Re: [TUTO] Utiliser les flags

Publié : ven. 16/juin/2017 9:06
par microdevweb
@boddhi,

C'est corrigé, merci pour cette remarque pertinente.