Outils d'utilisateurs

Outils du Site


bitset

Différences

Cette page vous donne les différences entre la révision choisie et la version actuelle de la page.

Lien vers cette vue

bitset [2016/04/23 13:33]
gbdivers
bitset [2016/07/05 18:54] (Version actuelle)
gbdivers
Ligne 1: Ligne 1:
  
-^ [[predicats|Chapitre précédent]] ^ [[programmez_avec_le_langage_c|Sommaire principal]] ^ [[intervalle|Chapitre suivant]] ^+^ [[predicats|Chapitre précédent]] ^ [[programmez_avec_le_langage_c|Sommaire principal]] ^ [[string_etendu|Chapitre suivant]] ^
  
-====== Les tableaux de bits ======+__ A rediger: cast vers d'autres types, bit shift__
  
-Vous avez déjà rencontrer la classe ''std::bitset'' dans le chapitre [[logique_et_calcul_booleen|]], pour afficher une séquence de bits. +====== [Aller plus loin] Les tableaux de bits ====== 
 + 
 +Vous avez déjà rencontré la classe ''std::bitset'' dans le chapitre [[logique_et_calcul_booleen|]], pour afficher une séquence de bits. 
  
 <code cpp main.cpp> <code cpp main.cpp>
Ligne 25: Ligne 27:
 </code> </code>
  
-Ce chapitre détaille l'utilisation de cette classe ''std::bitset'' et les notions de //flag// et //mask//. Les notions vues dans les chapitres [[logique_et_calcul_booleen|]] et [[boole_et_morgan|]] seront utilisées, n’hésitez pas les relire si nécessaire.+Ce chapitre détaille l'utilisation de cette classe ''std::bitset'' et les notions de //flag// et //mask//. Les notions vues dans les chapitres [[logique_et_calcul_booleen|]] et [[boole_et_morgan|]] seront utilisées, n’hésitez pas à les relire si nécessaire.
  
  
Ligne 57: Ligne 59:
 Pour faciliter la création de ''std::bitset'' à partir d'une entrée utilisateur (flux standard, fichier, etc), il est également possible d'initialiser un ''std::bitset'' à partir d'une chaîne de caractères. La syntaxe peut etre différente selon si vous utiliser une littérale chaîne ou un type ''std::string''. Pour faciliter la création de ''std::bitset'' à partir d'une entrée utilisateur (flux standard, fichier, etc), il est également possible d'initialiser un ''std::bitset'' à partir d'une chaîne de caractères. La syntaxe peut etre différente selon si vous utiliser une littérale chaîne ou un type ''std::string''.
  
-Le cas le plus simple est d'initialiser un ''std::bitset'' partir d'une chaîne complète, constituée des caractères ''0'' et ''1''. Dans ce cas, la syntaxe est identique pour une littérale et un ''std::string'' :+Le cas le plus simple est d'initialiser un ''std::bitset'' à partir d'une chaîne complète, constituée des caractères ''0'' et ''1''. Dans ce cas, la syntaxe est identique pour une littérale et un ''std::string'' :
  
 <code cpp main.cpp> <code cpp main.cpp>
Ligne 73: Ligne 75:
 Notez bien qu'il ne faut pas ajouter de préfixe dans la chaîne de caractères. Notez bien qu'il ne faut pas ajouter de préfixe dans la chaîne de caractères.
  
-Un ''std::bitset'' peut également être initialise a partir d'une sous-chaîne de caractères (c'est dire une partie d'une chaîne de caractères). La syntaxe est différentes entre une littérale et un ''st::string'' :+Un ''std::bitset'' peut également être initialisé à partir d'une sous-chaîne de caractères (c'est-à-dire une partie d'une chaîne de caractères). La syntaxe est différentes entre une littérale et un ''std::string'' :
  
   * pour une littérale, l'initialisation de ''std::bitset'' ne peut prendre qu'un seul argument optionnel supplémentaire : le nombre de caractères a conserver ;   * pour une littérale, l'initialisation de ''std::bitset'' ne peut prendre qu'un seul argument optionnel supplémentaire : le nombre de caractères a conserver ;
-  * pour un ''std::string'', ''std::bitset'' peut prendre deux arguments optionnels supplémentaires : la position du premier caractère et le nombre de caractères conserver.+  * pour un ''std::string'', ''std::bitset'' peut prendre deux arguments optionnels supplémentaires : la position du premier caractère et le nombre de caractères à conserver.
  
 Un exemple concret avec une littérale chaîne : Un exemple concret avec une littérale chaîne :
Ligne 110: Ligne 112:
     const std::string s { "1010101011" };     const std::string s { "1010101011" };
          
-    const std::bitset<8> b1 { s, 4 };    // commence l'indice 4 = "101011"+    const std::bitset<8> b1 { s, 4 };    // commence à l'indice 4 = "101011"
     std::cout << b1 << std::endl;     std::cout << b1 << std::endl;
          
-    const std::bitset<8> b2 { s, 4, 2 }; // commence l'indice 4 et conserve+    const std::bitset<8> b2 { s, 4, 2 }; // commence à l'indice 4 et conserve
                                          // 2 caractères = "10"                                          // 2 caractères = "10"
     std::cout << b2 << std::endl;     std::cout << b2 << std::endl;
Ligne 126: Ligne 128:
 </code> </code>
  
-N'oubliez pas qu'en C++, les indices dans les tableaux (et donc dans les chaines de caractères, puisqu'elles peuvent être considérées comme des tableaux de caractères) commencent l'indice 0. Donc l'indice 4 correspond au cinquième caractère :+N'oubliez pas qu'en C++, les indices dans les tableaux (et donc dans les chaines de caractères, puisqu'elles peuvent être considérées comme des tableaux de caractères) commencent à l'indice 0. Donc l'indice 4 correspond au cinquième caractère :
  
 <code> <code>
Ligne 135: Ligne 137:
 </code> </code>
  
-Pour terminer, il est possible d'utiliser d'autres caractères que ''0'' et ''1''. Pour cela, il faut fournir deux arguments supplémentaires, correspondent respectivement aux caractères utiliser la place de ''0'' et de ''1''.+Pour terminer, il est possible d'utiliser d'autres caractères que ''0'' et ''1''. Pour cela, il faut fournir deux arguments supplémentaires, correspondent respectivement aux caractères à utiliser à la place de ''0'' et de ''1''.
  
 <code cpp main.cpp> <code cpp main.cpp>
Ligne 163: Ligne 165:
 <note>**Ordres des arguments et arguments optionnels** <note>**Ordres des arguments et arguments optionnels**
  
-En C++, les arguments sont identifies par leur position dans l'appel d'une fonction. Par exemple pour initialiser ''std::bitset'' (avec ''position'' qui représente la position du premier caractère et ''taille'' qui correspond au nombre de caractères conserver : +En C++, les arguments sont identifiés par leur position dans l'appel d'une fonction. Par exemple pour initialiser ''std::bitset'' (avec ''position'' qui représente la position du premier caractère et ''taille'' qui correspond au nombre de caractères à conserver : 
  
 <code> <code>
Ligne 177: Ligne 179:
 </code> </code>
  
-Dans ce code, le compilateur ne va pas utiliser ''taille'' pour le nombre de caractères et ''position'' pour la position du premier caractère (donc prendre 4 caractères partir de la position 2), mais va prendre 2 caractères partir de la position 4.+Dans ce code, le compilateur ne va pas utiliser ''taille'' pour le nombre de caractères et ''position'' pour la position du premier caractère (donc prendre 4 caractères à partir de la position 2), mais va prendre 2 caractères à partir de la position 4.
  
 Pour la même raison, si on fournit un argument optionnel, les arguments optionnels qui le précédent ne sont plus optionnels. Pour la même raison, si on fournit un argument optionnel, les arguments optionnels qui le précédent ne sont plus optionnels.
Ligne 210: Ligne 212:
 </code> </code>
  
-Dans le cas d'une valeur entière, le compilateur est autorisé à créer automatiquement et de façon transparente un ''std::bitset'' à partir de cette valeur. C'est à dire à remplacer :+Dans le cas d'une valeur entière, le compilateur est autorisé à créer automatiquement et de façon transparente un ''std::bitset'' à partir de cette valeur. C'est-à-dire à remplacer :
  
 <code> <code>
Ligne 258: Ligne 260:
 Dans ce cas, ''std::bitset'' sera affiche en utilisant les caractères ''0'' et ''1'', avec autant de caractères que définie dans l'argument //template// de ''std::bitset'' (donc en complétant avec ''0'' si nécessaire). Dans ce cas, ''std::bitset'' sera affiche en utilisant les caractères ''0'' et ''1'', avec autant de caractères que définie dans l'argument //template// de ''std::bitset'' (donc en complétant avec ''0'' si nécessaire).
  
-La fonction ''to_string'' permet de transformer un ''std::bitset'' en une chaîne de caractères, en utilisant par défaut les caractères ''0'' et ''1'' (c'est l’opération inverse de l'initialisation avec une chaîne). Cette fonction peut prendre deux arguments optionnels, correspondant aux caractères utiliser respectivement pour ''0'' et ''1''. +La fonction ''to_string'' permet de transformer un ''std::bitset'' en une chaîne de caractères, en utilisant par défaut les caractères ''0'' et ''1'' (c'est l’opération inverse de l'initialisation avec une chaîne). Cette fonction peut prendre deux arguments optionnels, correspondant aux caractères à utiliser respectivement pour ''0'' et ''1''. 
  
 La chaîne de caractères produite peut être conservée dans une variable ou être directement affichée avec ''std::cout''. La chaîne de caractères produite peut être conservée dans une variable ou être directement affichée avec ''std::cout''.
Ligne 287: Ligne 289:
 Conceptuellement, ''std::bitset'' est un tableau compact de booléens. Il est donc possible de manipuler directement chaque bit comme une valeur booléenne, de la lire ou de la modifier directement dans ''std::bitset''. Conceptuellement, ''std::bitset'' est un tableau compact de booléens. Il est donc possible de manipuler directement chaque bit comme une valeur booléenne, de la lire ou de la modifier directement dans ''std::bitset''.
  
-Pour connaitre la taille d'un ''std::bitset'' (c'est dire connaitre la valeur de l'argument //template// ''TAILLE'' utilise pour initialiser le ''std::bitset''), vous pouvez utiliser la fonction ''size''.+Pour connaitre la taille d'un ''std::bitset'' (c'est-à-dire connaitre la valeur de l'argument //template// ''TAILLE'' utilise pour initialiser le ''std::bitset''), vous pouvez utiliser la fonction ''size''.
  
 <note>Vous voyez ici l’intérêt d'avoir une interface cohérente : beaucoup de classe de la bibliothèque standard représentant un tableau proposent la fonction ''size'' pour connaitre la taille du tableau (''std::vector'', ''std::array'', ''std::string'', etc). Avoir un interface cohérente simplifie la mémorisation et évite les erreurs. Conservez cette idée en tête lorsque vous créerez vos propres interfaces.</note> <note>Vous voyez ici l’intérêt d'avoir une interface cohérente : beaucoup de classe de la bibliothèque standard représentant un tableau proposent la fonction ''size'' pour connaitre la taille du tableau (''std::vector'', ''std::array'', ''std::string'', etc). Avoir un interface cohérente simplifie la mémorisation et évite les erreurs. Conservez cette idée en tête lorsque vous créerez vos propres interfaces.</note>
Ligne 383: Ligne 385:
 En complément de l’opérateur d'indexation ''[]'', qui permet d’accéder aux bits d'un ''std::bitset'' en lecture ET en écriture, la classe ''std::bitset'' propose également plusieurs fonctions plus spécialisées, pour accéder aux bits en lecture OU en écriture. En complément de l’opérateur d'indexation ''[]'', qui permet d’accéder aux bits d'un ''std::bitset'' en lecture ET en écriture, la classe ''std::bitset'' propose également plusieurs fonctions plus spécialisées, pour accéder aux bits en lecture OU en écriture.
  
-<note>Une seconde différence importante est que ces fonctions vérifient les acces en dehors des limites de ''std::bitset'' et lancer une exception de type ''std::out_of_range'' si vous essayez d'utiliser un index invalide. +<note>Une seconde différence importante est que ces fonctions vérifient les accès en dehors des limites de ''std::bitset'' et lancer une exception de type ''std::out_of_range'' si vous essayez d'utiliser un index invalide. 
  
-La gestion des erreurs et les exceptions seront vu dans la partie sur la création de bibliothèque, mais retenez que la vérification systématique des accès est assimilée de la programmation défensive, ce qui n'est pas forcement une bonne pratique.</note>+La gestion des erreurs et les exceptions seront vu dans la partie sur la création de bibliothèque, mais retenez que la vérification systématique des accès est assimilée à de la programmation défensive, ce qui n'est pas forcément une bonne pratique.</note>
  
 Les fonctions sont les suivantes : Les fonctions sont les suivantes :
  
   * ''test'' pour lire une valeur ;   * ''test'' pour lire une valeur ;
-  * ''set'' pour modifier une valeur (par défaut pour la mettre ''true'') ; +  * ''set'' pour modifier une valeur (par défaut pour la mettre à ''true'') ; 
-  * ''reset'' pour mettre une valeur ''false'' ; +  * ''reset'' pour mettre une valeur à ''false'' ; 
-  * ''flip'' pour inverser une valeur (c'est dire que les bits valant ''true'' passent ''false'' et vice-versa).+  * ''flip'' pour inverser une valeur (c'est-à-dire que les bits valant ''true'' passent à ''false'' et vice-versa).
  
-Ces fonctions prennent comme argument l'indice du bit modifier. les fonctions ''set'', ''reset'' et ''flip'' peuvent également être appelée sans argument, ce qui a pour effet de modifier tous les bits. Pour terminer, la fonction ''set'' peut prendre deux arguments : l'indice du bit modifier et la valeur booléenne à définir.+Ces fonctions prennent comme argument l'indice du bit à modifier. les fonctions ''set'', ''reset'' et ''flip'' peuvent également être appelée sans argument, ce qui a pour effet de modifier tous les bits. Pour terminer, la fonction ''set'' peut prendre deux arguments : l'indice du bit à modifier et la valeur booléenne à définir.
  
 <code cpp main.cpp> <code cpp main.cpp>
Ligne 494: Ligne 496:
 </code> </code>
  
-<note>Il existe de nombreuses habitudes de programmation. Par exemple comme dans le code précédent, les préfixes "is" et "has" sont utilisés respectivement les états "est" ou "n'est pas" et les états "a" ou "n'a pas". Ainsi, ''is_visible'' signifie littéralement "est visible" et sera vraie quand la fenêtre est visible et fausse dans le cas contraire.+<note>Il existe de nombreuses habitudes de programmation. Par exemple comme dans le code précédent, les préfixes "is" et "has" sont utilisés respectivement les états "est" ou "n'est pas" et les états "a" ou "n'a pas". Ainsi, ''is_visible'' signifie littéralement "est visible" et sera vraie quand la fenêtre est visible et fausse dans le cas contraire.</note>
  
 Cependant, vous avez vu qu'un booléen en mémoire n'est pas représenté par un bit, mais par un octet en général (soit 8 bits). Cela signifie donc une consommation mémoire inutilement plus importante. Cependant, vous avez vu qu'un booléen en mémoire n'est pas représenté par un bit, mais par un octet en général (soit 8 bits). Cela signifie donc une consommation mémoire inutilement plus importante.
Ligne 530: Ligne 532:
 </code> </code>
  
-<note>Vous voyez ici un effet indésirable des optimisation : le code perd en lisibilité. Sans la documentation, il est impossible de savoir que ''0b001'' représente une fenêtre visible, non déplaçable et sans barre de titre, alors que ''is_visible'', ''is_movable'' et ''has_title'' sont suffisamment compréhensible. +<note> 
 +Vous voyez ici un effet indésirable des optimisation : le code perd en lisibilité. Sans la documentation, il est impossible de savoir que ''0b001'' représente une fenêtre visible, non déplaçable et sans barre de titre, alors que ''is_visible'', ''is_movable'' et ''has_title'' sont suffisamment compréhensibles.
  
 +Et plus généralement, lorsque vous concevrez un code, vous devrez faire des compromis entre vos objectifs de qualité logicielle (lisibilité, évolutivité, fiabilité, etc) et vos contraintes (temps de développement, moyens humains, etc).
 </note> </note>
  
Ligne 538: Ligne 541:
 ==== Le masquage ==== ==== Le masquage ====
  
-Le masquage est un concept générique en informatique, qui consiste a definir un sous-ensemble sur lequel sera appliquer une modification (vous pouvez par exemple retrouver ce concept dans les masques de calque dans un logiciel de dessin tel que Gimp).+Le masquage est un concept générique en informatique, qui consiste à définir un sous-ensemble sur lequel sera appliqué une modification (vous pouvez par exemple retrouver ce concept dans les masques de calque dans un logiciel de dessin tel que Gimp).
  
-Pour prendre un exemple concret, imaginez que vous avez la valeur ''0b11001110'' et que vous souhaitez modifier que les quatre premiers bits (en partant de la droite). En appliquant les operations precedentes, vous obtiendrez :+Pour prendre un exemple concret, imaginez que vous avez la valeur ''0b11001110'' et que vous souhaitez modifier que les quatre premiers bits (en partant de la droite). En appliquant les opérations précédentes, vous obtiendrez :
  
 ^ Operation ^ Resultat       ^ Commentaire                                      ^ ^ Operation ^ Resultat       ^ Commentaire                                      ^
Ligne 551: Ligne 554:
 | count     | ''3''          | il y a 3 bits a 1 dans les quatres derniers bits | | count     | ''3''          | il y a 3 bits a 1 dans les quatres derniers bits |
  
-Les bits sur les quels est applique ou non les modifications est appele le masque. En pratique, il est possible de definir n'importe quelle sequence de bits dans un masque, vous n'etes pas limites a definir une sequence continue comme dans l'exemple precedent.+Les bits sur les quels est appliqués ou non les modifications sont appelés le masque. En pratique, il est possible de définir n'importe quelle séquence de bits dans un masque, vous n’êtes pas limités à définir une séquence continue comme dans l'exemple précédent.
  
-Definir un masque est assez simple : il faut pouvoir definir pour chaque bit si celui-ci sera modifie (''true'') ou non (''false''). Un masque est donc en fait un ''std::bitset'', pour lequel vous affecter ''true'' aux bits qui seront pourront etre modifies.+Définir un masque est assez simple : il faut pouvoir définir pour chaque bit si celui-ci sera modifié (''true'') ou non (''false''). Un masque est donc en fait un ''std::bitset'', pour lequel vous affectez ''true'' aux bits qui seront pourront être modifiés.
  
-Par exemple, dans l'exemple precedent, le masque est le ''std::bitset'' suivant : ''0b00001111''.+Par exemple, dans l'exemple précédent, le masque est le ''std::bitset'' suivant : ''0b00001111''.
  
-Pour appliquer le masque sur un ''std::bitset'', vous utilisez ensuite les opérateurs logiques bit bit que vous avez deja vu dans le chapitre [[logique_et_calcul_booleen|]] : +Pour appliquer le masque sur un ''std::bitset'', vous utilisez ensuite les opérateurs logiques bit à bit que vous avez déjà vu dans le chapitre [[logique_et_calcul_booleen|]] (en particulier "ET" et "OU") 
  
   * "ET" ''&'' ("AND") ;   * "ET" ''&'' ("AND") ;
Ligne 564: Ligne 567:
   * "Negation" ''~'' ("NOT").   * "Negation" ''~'' ("NOT").
  
-Pour rappel, voici le tableau recapitulatif de ces operateurs :+Pour rappel, voici le tableau récapitulatif de ces opérateurs :
  
 ^  ''a''  ^  ''b''  ^  ''~a''  ^   ''a & b''  ^  ''a | b''  ^  ''a ^ b''  ^ ^  ''a''  ^  ''b''  ^  ''~a''  ^   ''a & b''  ^  ''a | b''  ^  ''a ^ b''  ^
Ligne 572: Ligne 575:
 |  1      |  1      |  0       |  1           |  1          |  0          | |  1      |  1      |  0       |  1           |  1          |  0          |
  
- 
- 
- 
- 
- 
-tester un bit : mask, flag, opérateur ET bit à bit, test() 
- 
-forcer un bit : OU bit a bitque repr 
- 
- 
- 
- 
-===== Bit-shift ===== 
- 
-===== cast vers d'autres types ===== 
  
 ===== Exercices ===== ===== Exercices =====
Ligne 595: Ligne 583:
   * trouver la plus longue chaîne de 1 dans la représentation   * trouver la plus longue chaîne de 1 dans la représentation
  
-Exercices avancees (necessite de connaitre les classes) :+Exercices avancés (nécessite de connaitre les classes) : 
 + 
 +  * créer une classe bitset_view 
 +  * créer une classe bitset_array_view
  
-  * creer une classe bitset_view +^ [[predicats|Chapitre précédent]] ^ [[programmez_avec_le_langage_c|Sommaire principal]] ^ [[string_etendu|Chapitre suivant]] ^
-  * creer une classe bitset_array_view+
  
-^ [[predicats|Chapitre précédent]] ^ [[programmez_avec_le_langage_c|Sommaire principal]] ^ [[intervalle|Chapitre suivant]] ^ 
bitset.1461411199.txt.gz · Dernière modification: 2016/04/23 13:33 par gbdivers