Légende des schémas
N

Index d'un bit du champs de bits de la variable originale, marque la fin d'un octet (en notation hexadécimale)

N

Index d'un bit du champs de bits de la variable originale, marque un position intermédiaire d'un octet (en notation hexadécimale)

N

Index d'un bit du champs de bits de la variable originale, marque le début d'un octet (en notation hexadécimale)

N

Contenu binaire du bit de la variable originale à l'index (en notation binaire: 0 ou 1)

N

Contenu binaire du bit du masque à l'index (en notation binaire: 0 ou 1)

N

Contenu binaire du bit résultant de l'opération du masque sur la variable originale à l'index (en notation binaire: 0 ou 1)

 

 

 

 

 

Pourquoi cet objet

L'intérêt de cet objet n'est pas de se substituer à une variable, bien que cela soit possible. Non, il réside dans la propriété même d'une variable : stocker des valeurs et notamment de stocker plusieurs valeurs à l'intérieur d'une seule afin d'optimiser la mémoire.

Le cas le plus emblématique est la variable BOOL. C'est une variable de type int, c'est à dire qu'elle occupe 4 octets (32 bits) en mémoire alors qu'elle n'est destinée à accueillir que deux valeurs : le 0 (FALSE) et le 1 (TRUE). Donc elle utilise qu'un bit, les autres (31) ne le sont pas. On peut dire que ces 31 bits sont gaspillés.

C'est bien sûr un cas extrême, mais bien souvent l'on a besoin uniquement de stocker une grande quantité d'états de type Non/Oui et il faut se résoudre à utiliser une variable pour chacun d'eux dont uniquement un bit sera réellement exploité.

La solution réside dans l'exploitation, non pas d'une variable comme entité propre, mais dans chacun des bits qui la compose.

Cet objet est à utiliser uniquement avec des variables décimales (char, short, int, long, longlong) non flottantes (float, double).

 

 

 

 

 

Décomposition d'une variable

L'élément primaire est le bit, qui ne peut accepter que deux états, le 0 et le 1. On fait tout avec cela.

Pour pouvoir stocker des informations supérieures à 1, on a assemblé ces bits par paquets de 8; c'est l'octet. Les bits sont positionnés l'un à la suite de l'autre en commençant par la droite.

Le schéma suivant montre la représentation d'un octet :

07 06 05 04 03 02 01 00

Champs de bits

0 0 0 0 0 0 0 0 Valeur originale

Afin de pouvoir stocker un nombre dans ces cases, il faut le décomposer en puissances de 2 (1, 2, 4, 8, 16, 32, 64, etc...), par exemple 140 se décompose en :

(1 * 2^7) + (0 * 2^6) + (0 * 2^5)+ (0 * 2^4) + (1 * 2^3) + (1 * 2^2) + (0 * 2^1) + (0 * 2^0) = 128 + 8 + 4 = 140, soit :

07 06 05 04 03 02 01 00

Champs de bits

1 0 0 0 1 1 0 0 Valeur originale

Si l'on pose tous les bits d'un octet, on obtient le nombre 255. Donc un octet (composé de 8 bits) peut contenir un nombre pouvant s'étaler de 0 à 255.

Si l'on a besoin de stocker un nombre supérieur, il suffit de "coller" deux octets, on a ainsi 16 bits qui peuvent contenir un nombre pouvant s'étaler de 0 à 65535. On peut "coller" deux, quatre ou huit 8 octets (oubliez la possibilité de "coller" 3, 5 ou 6 octets).

C'est cette possibilité de manipuler chacun des bits d'une variable qui nous est utile pour l'objet EValue.

A titre indicatif, une variable de type char est composé d'un octet (soit 8 bits), le type short de deux octets (16 bits), le int et le long de quatre octets (32 bits) et le longlong de huit octets (64 bits).

 

 

 

 

 

Instancier un objet EValue

L'objet EValue est un template, il ne s'instancie pas exactement comme une classe. Vous devez spécifier en plus un type de portée de l'objet :

Objet père + <Type de portée > + nom de l'objet instancié(argument d'initialisation du constructeur "optionnel");

Description :

• Instancier un objet EValue de type uchar initialisé avec la valeur 140 (10001100).

Code :

EValue <uchar> eValue( 140 );

Vue :

07 06 05 04 03 02 01 00

Champs de bits

1 0 0 0 1 1 0 0 Valeur originale

Cet objet, nommé eValue, est une instanciation d'un objet EValue, considère le type de l'objet comme un uchar, et initialise la variable membre m_tValue avec la valeur 140.

L'objet ne peut travailler que sur une étendue d'un octet (8 bits) car le type uchar a une densité d'un octet. Si vous essayez d'accéder à des bits au delà de cette limite, il n'y aura aucun effet.

Si l'on désire travailler sur 8 octets (64 bits), on doit instancier l'objet avec le type longlong (ou ulonglong).

Description :

• Instancier un objet EValue de type ulonglong initialisé avec la valeur 9000000000000000000 (01111100 11100110 01101100 01010000 11100010 10000100 00000000 00000000).

Code :

EValue <ulonglong> eValue( 9000000000000000000 ); // 9.000.000.000.000.000.000

Vue :

1F 1E 1D 1C 1B 1A 19 18 17 16 15 14 13 12 11 10 0F 0E 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00
1 1 1 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
3F 3E 3D 3C 3B 3A 39 38 37 36 35 34 33 32 31 30 2F 2E 2D 2C 2B 2A 29 28 27 26 25 24 23 22 21 20
0 1 1 1 1 1 0 0 1 1 1 0 0 1 1 0 0 1 1 0 1 1 0 0 0 1 0 1 0 0 0 0

 

 

 

 

 

Manipuler les bits d'une variable

Pour manipuler un bit d'une variable on a besoin d'une variable sur laquelle travailler, d'un masque de bits servant de calque et d'un opérateur de bits.

La variable contient les bits qui doivent être manipulés, le masque de bits contient les coordonnées du/des bit(s) à manipuler et l'opérateur de bits indique l'opération à effectuer.

Ajouter un bit

Il s'agit de mettre la valeur 1 dans l'un des bits de la variable. Le masque de bits doit contenir le(s) bit(s) à poser et l'opérateur de bits est le caractère | (or, transposé dans l'objet EValue par les fonctions EValue::MaskAdd...(...)).

Description :

• Instancier un objet EValue de type uchar initialisé avec la valeur 140 (10001100),
• Ajouter le masque de bits 0x20 (001000000),
• Ajouter le masque de bits 0x1F (000111111).

Code :

EValue <uchar> eValue( 140 );

eValue.TraceEx();
eValue.MaskAdd( 0x20 );
eValue.TraceEx();
eValue.MaskAdd( 0x1F );
eValue.TraceEx();

Sortie :

### Object EValue Trace #
# Object address='0x0012F483', size of='1' byte(s) ('8' bits).
# Value:
# Decimal='-116'(signed) '140'(unsigned), Hexadecimal='0x8C'.
# Binary = 10001100
# Equal. = ========
# Pos maj= 00000000
# Pos min= 76543210
### End #

### Object EValue Trace #
# Object address='0x0012F483', size of='1' byte(s) ('8' bits).
# Value:
# Decimal='-84'(signed) '172'(unsigned), Hexadecimal='0xAC'.
# Binary = 10101100
# Equal. = ========
# Pos maj= 00000000
# Pos min= 76543210
### End #

### Object EValue Trace #
# Object address='0x0012F483', size of='1' byte(s) ('8' bits).
# Value:
# Decimal='-65'(signed) '191'(unsigned), Hexadecimal='0xBF'.
# Binary = 10111111
# Equal. = ========
# Pos maj= 00000000
# Pos min= 76543210
### End #

Vue :

07 06 05 04 03 02 01 00

Champs de bits

1 0 0 0 1 1 0 0 Valeur originale

07 06 05 04 03 02 01 00

Champs de bits

1 0 0 0 1 1 0 0 Valeur originale
0 0 1 0 0 0 0 0 Ajouter 20
1 0 1 0 1 1 0 0 Résultat

07 06 05 04 03 02 01 00

Champs de bits

1 0 1 0 1 1 0 0 Valeur originale
0 0 0 1 1 1 1 1 Ajouter 1F
1 0 1 1 1 1 1 1 Résultat

Que c'est-il passé ?

Tout d'abord il faut savoir que le masque de bits vient se calquer sur la variable, le bit à la position 0x00 du masque ne travaillera que sur le bit à la position 0x00 de la variable, le bit à la position 0x01 du masque ne travaillera que sur le bit 0x01 de la variable, etc... Les opérations se font en parallèle.

Si le bit 0x00 du masque contient la valeur 1, le bit correspondant dans la variable est mis à 1. Si le bit 0x00 du masque contient la valeur 0 alors le bit correspondant dans la variable n'est pas modifié, etc...

Dans notre exemple, seul le bit 0x05 du masque est posé, donc l'opérateur de bits | va mettre la valeur 1 au bit 0x05 de la variable. Les autres bits de la variable ne sont pas touchés.

Supprimer un bit

Il s'agit de mettre la valeur 0 dans l'un des bits de la variable. Le masque de bits doit contenir le(s) bit(s) à supprimer et l'opérateur de bits est le caractère & (and, transposé dans l'objet EValue par les fonctions EValue::MaskSuppress...(...)).

Description :

• Instancier un objet EValue de type uchar initialisé avec la valeur 140 (10001100),
• Supprimer le masque de bits 0x0C (00001100).

Code :

EValue <uchar> eValue( 140 );

eValue.TraceEx();
eValue.MaskSuppress( 0x0C );
eValue.TraceEx();

Sortie :

### Object EValue Trace #
# Object address='0x0012F483', size of='1' byte(s) ('8' bits).
# Value:
# Decimal='-116'(signed) '140'(unsigned), Hexadecimal='0x8C'.
# Binary = 10001100
# Equal. = ========
# Pos maj= 00000000
# Pos min= 76543210
### End #

### Object EValue Trace #
# Object address='0x0012F483', size of='1' byte(s) ('8' bits).
# Value:
# Decimal='-128'(signed) '128'(unsigned), Hexadecimal='0x80'.
# Binary = 10000000
# Equal. = ========
# Pos maj= 00000000
# Pos min= 76543210
### End #

Vue :

07 06 05 04 03 02 01 00

Champs de bits

1 0 0 0 1 1 0 0 Valeur originale

07 06 05 04 03 02 01 00

Champs de bits

1 0 0 0 1 1 0 0 Valeur originale
0 0 0 0 1 1 0 0 Supprimer 0C
1 0 0 0 0 0 0 0 Résultat

Que c'est-il passé ?

Si le bit 0x00 du masque contient la valeur 1, le bit correspondant dans la variable est mis à 0. Si le bit 0x00 du masque contient la valeur 0 alors le bit correspondant dans la variable n'est pas modifié, etc...

Dans notre exemple, seuls les bits 0x02 et 0x03 du masque sont posés, donc l'opérateur de bits & va mettre la valeur 0 au bit 0x02 et bit 0x03 de la variable. Les autres bits de la variable ne sont pas touchés.

Tester un bit

Il s'agit de tester si un ou des bits sont positionnés à 1 dans une variable. Là aussi on utilise l'opérateur &.

Description :

• Instancier un objet EValue de type uchar initialisé avec la valeur 140 (10001100),
• Tester si le masque de bits 0x08 (00001000) est présent dans l'objet,
• Tester si le masque de bits 0x20 (00100000) est présent dans l'objet,
• Tester si le masque de bits 0x88 (10001000) est présent dans l'objet,
• Tester si le masque de bits 0xA8 (10101000) est présent dans l'objet.

Code :

EValue <uchar> eValue( 140 );
TCHAR *pszNoYes[]={ _T("Non"), _T("Oui") };

eValue.TraceEx();
ETrace::DoEx( _T("Bit 0x03 posé ? %s!\n"), pszNoYes[eValue.MaskPresentGet( 0x08 )] );
ETrace::DoEx( _T("Bit 0x05 posé ? %s!\n"), pszNoYes[eValue.MaskPresentGet( 0x20 )] );
ETrace::DoEx( _T("Bit 0x03 et 0x07 posés ? %s!\n"), pszNoYes[eValue.MaskPresentGet( 0x88 )] );
ETrace::DoEx( _T("Bit 0x03, 0x05 et 0x07 posés ? %s!\n"), pszNoYes[eValue.MaskPresentGet( 0xA8 )] );

Sortie :

### Object EValue Trace #
# Object address='0x0012F483', size of='1' byte(s) ('8' bits).
# Value:
# Decimal='-116'(signed) '140'(unsigned), Hexadecimal='0x8C'.
# Binary = 10001100
# Equal. = ========
# Pos maj= 00000000
# Pos min= 76543210
### End #

Bit 0x03 posé ? Oui!
Bit 0x05 posé ? Non!
Bit 0x03 et 0x07 posés ? Oui!
Bit 0x03, 0x05 et 0x07 posés ? Non!

Vue :

07 06 05 04 03 02 01 00

Champs de bits

1 0 0 0 1 1 0 0 Valeur originale

07 06 05 04 03 02 01 00

Champs de bits

1 0 0 0 1 1 0 0 Valeur originale
0 0 0 0 1 0 0 0 Tester 0x08
0 0 1 0 0 0 0 0 Tester 0x20
1 0 0 0 1 0 0 0 Tester 0x88
1 0 1 0 1 0 0 0 Tester 0xA8

 

 

 

 

 

Tirer partie de l'objet EValue

A partir d'un exemple simple, nous allons voir comment utiliser l'objet EValue au mieux en quatre étapes.

Nous avons un programme et nous désirons pouvoir stocker 5 informations :

- faut-il afficher les astuces au démarrage (oui/non) ?
- faut-il demander une confirmation de fermeture du programme (oui/non) ?
- faut-il afficher la fenêtre du programme au dessus des autres (oui/non) ?
- faut-il afficher une ombre derrière la fenêtre du programme (oui/non) ?
- quelle est la langue à utiliser (en=0/fr=1/it=2/ge=3/sp=4) ?

Etape 1

On peut écrire le code suivant :

Code :

BOOL bTipAtStart = TRUE; /* Afficher astuces au démarrage du programme (O/N) ? */
BOOL bPrgCloseMessage = TRUE; /* Demander une confirmation à la fermeture du programme (O/N) ? */
BOOL bWindowOnTop = FALSE; /* Afficher la fenêtre du programme au dessus des autres (O/N) ? */
BOOL bWindowShadow = TRUE; /* Afficher une ombre sous la fenêtre du programme (O/N) ? */

#define dfLanguageEnglish = 0; /* Utiliser la langue anglaise */
#define dfLanguageFrench = 1; /* Utiliser la langue française */
#define dfLanguageItalian = 2; /* Utiliser la langue italienne */
#define dfLanguageGerman = 3; /* Utiliser la langue allemande */
#define dfLanguageSpanish = 4; /* Utiliser la langue espagnole */

long lLanguageToUse = dfLanguageItalian;

La déclaration de ces variables occupe 20 octets, soit 160 bits. Comme on peut le constater seulement 7 bits sont utilisés réellement (soit 4%), donc 153 bits sont gaspillés (soit ±19 octets).

Etape 2

On peut optimiser cela par le code suivant :

Code :

char cTipAtStart = TRUE; /* Afficher astuces au démarrage du programme (O/N) ? */
char cPrgCloseMessage = TRUE; /* Demander une confirmation à la fermeture du programme (O/N) ? */
char cWindowOnTop = FALSE; /* Afficher la fenêtre du programme au dessus des autres (O/N) ? */
char cWindowShadow = TRUE; /* Afficher une ombre sous la fenêtre du programme (O/N) ? */

#define dfLanguageEnglish = 0; /* Utiliser la langue anglaise */
#define dfLanguageFrench = 1; /* Utiliser la langue française */
#define dfLanguageItalian = 2; /* Utiliser la langue italienne */
#define dfLanguageGerman = 3; /* Utiliser la langue allemande */
#define dfLanguageSpanish = 4; /* Utiliser la langue espagnole */

char cLanguageToUse = dfLanguageItalian;

Là, la déclaration de ces variables occupe 5 octets (soit 40 bits). Comme on peut le constater seulement 7 bits sont utilisés réellement (soit 17%), donc 33 bits sont gaspillés (soit ±4 octets).

Etape 3

C'est un progrès mais l'on peut faire mieux en utilisant l'objet EValue :

Code :

enum {
  TipAtStart = 0x01, /* 00000001 en binaire*/ /* Afficher astuces au démarrage du programme (O/N) ? */
  PrgCloseMessage = 0x02, /* 00000010 en binaire*/ /* Demander une confirmation à la fermeture du programme (O/N) ? */
  WindowOnTop = 0x04, /* 00000100 en binaire*/ /* Afficher la fenêtre du programme au dessus des autres (O/N) ? */
  WindowShadow = 0x08, /* 00001000 en binaire*/ /* Afficher une ombre sous la fenêtre du programme (O/N) ? */
  };
#define dfLanguageEnglish = 0; /* Utiliser la langue anglaise */
#define dfLanguageFrench = 1; /* Utiliser la langue française */
#define dfLanguageItalian = 2; /* Utiliser la langue italienne */
#define dfLanguageGerman = 3; /* Utiliser la langue allemande */
#define dfLanguageSpanish = 4; /* Utiliser la langue espagnole */

EValue <uchar> eValConfig( TipAtStart | PrgCloseMessage | WindowShadow );
char cLanguageToUse = dfLanguageItalian;

Vue :

07 06 05 04 03 02 01 00

Champs de bits

0 0 1 0 1 0 1 1 Valeur originale
0 0 0 0 0 0 0 [1] TipAtStart
0 0 0 0 0 0 [1] 0 PrgCloseMessage
0 0 0 0 0 [1] 0 0 WindowOnTop
0 0 0 0 [1] 0 0 0 WindowShadow

La déclaration de ces variables occupe 2 octets (soit 16 bits). Comme on peut le constater 7 bits sont utilisés réellement (soit 43%), donc 9 bits sont gaspillés (soit ±1 octet).

Il y a encore une technique d'optimisation possible.

Etape 4

Jusqu'à présent nous nous sommes focalisé sur la possibilité d'exploiter l'objet pour stocker des valeurs de types OUI/NON en n'utilisant qu'un bit. Mais il est possible d'utiliser les bits par paquets.

La variable stockant la langue à utiliser peut être aussi stockée dans un objet EValue ? Sachant que ses valeurs possibles s'étendent de 0 (en) à 4 (sp 111 en binaire), on peut caser ces trois octets dans les bits 0x04, 0x05 et 0x6 par la méthode suivante :

Code :

enum {
  TipAtStart = 0x01, /* 00000001 en binaire*/ /* Afficher astuces au démarrage du programme (O/N) ? */
  PrgCloseMessage = 0x02, /* 00000010 en binaire*/ /* Demander une confirmation à la fermeture du programme (O/N) ? */
  WindowOnTop = 0x04, /* 00000100 en binaire*/ /* Afficher la fenêtre du programme au dessus des autres (O/N) ? */
  WindowShadow = 0x08, /* 00001000 en binaire*/ /* Afficher une ombre sous la fenêtre du programme (O/N) ? */

  LanguageEnglish = ( 0 << 4 ), /* 00000000 en binaire*/ /* Utiliser la langue anglaise */
  LanguageFrench = ( 1 << 4 ), /* 00010000 en binaire*/ /* Utiliser la langue française */
  LanguageItalian = ( 2 << 4 ), /* 00100000 en binaire*/ /* Utiliser la langue italienne */
  LanguageGerman = ( 3 << 4 ), /* 00110000 en binaire*/ /* Utiliser la langue allemande */
  LanguageSpanish = ( 4 << 4 ), /* 01000000 en binaire*/ /* Utiliser la langue espagnole */
  LanguageAll = ( LanguageEnglish | LanguageFrench | LanguageItalian | LanguageGerman | LanguageSpanish ), /* 01110000 en binaire*/
  };

Vue :

07 06 05 04 03 02 01 00

Champs de bits

0 0 1 0 1 0 1 1 Valeur originale
0 0 0 0 0 0 0 [1] TipAtStart
0 0 0 0 0 0 [1] 0 PrgCloseMessage
0 0 0 0 0 [1] 0 0 WindowOnTop
0 0 0 0 [1] 0 0 0 WindowShadow
0 [0 0 0] 0 0 0 0 LanguageEnglish
0 [0 0 1] 0 0 0 0 LanguageFrench
0 [0 1 0] 0 0 0 0 LanguageItalian
0 [0 1 1] 0 0 0 0 LanguageGerman
0 [1 0 0] 0 0 0 0 LanguageSpanish
0 [1 1 1] 0 0 0 0 LanguageAll

Pour récupérer la langue utilisée, il suffit de tester les bits 0x04, 0x05 et 0x06 en utilisant le masque 0x70 (01110000 en binaire) défini à l'énumération LanguageAll de la manière suivante :

Langue à utiliser = objet EValue & LanguageAll;

Pour fixer la langue à utiliser, il suffit de supprimer tous les bits concernant les langues puis d'ajouter ceux de la langue à utiliser. Il est important de supprimer d'abord tous les bits concernant les langues sinon il pourrait y avoir une superposition des bits de l'ancienne langue et de la nouvelle (la fonction EValue::MaskSuppressAdd( T tMaskToSuppress, T tMaskToAdd ); a été spécialement écrite pour cela) :

MaskSuppressAdd( LanguageAll, LanguageFrench );

Code :

enum {
  TipAtStart = 0x01, /* 00000001 en binaire*/ /* Afficher astuces au démarrage du programme (O/N) ? */
  PrgCloseMessage = 0x02, /* 00000010 en binaire*/ /* Demander une confirmation à la fermeture du programme (O/N) ? */
  WindowOnTop = 0x04, /* 00000100 en binaire*/ /* Afficher la fenêtre du programme au dessus des autres (O/N) ? */
  WindowShadow = 0x08, /* 00001000 en binaire*/ /* Afficher une ombre sous la fenêtre du programme (O/N) ? */

  LanguageEnglish = ( 0 << 4 ), /* 00000000 en binaire*/ /* Utiliser la langue anglaise */
  LanguageFrench = ( 1 << 4 ), /* 00010000 en binaire*/ /* Utiliser la langue française */
  LanguageItalian = ( 2 << 4 ), /* 00100000 en binaire*/ /* Utiliser la langue italienne */
  LanguageGerman = ( 3 << 4 ), /* 00110000 en binaire*/ /* Utiliser la langue allemande */
  LanguageSpanish = ( 4 << 4 ), /* 01000000 en binaire*/ /* Utiliser la langue espagnole */
  LanguageAll = ( LanguageEnglish | LanguageFrench | LanguageItalian | LanguageGerman | LanguageSpanish ), /* 01110000 en binaire*/
  };

EValue <uchar> eValConfig( TipAtStart | PrgCloseMessage | WindowShadow | LanguageItalian );

// Première façon de déterminer la langue à utiliser
switch( eValConfig.MaskGet( LanguageAll ) )
  {
  case LanguageEnglish : ETrace::Do( _T("La langue anglaise est sélectionnée.\n\n") ); break;
  case LanguageFrench : ETrace::Do( _T("La langue française est sélectionnée.\n\n") ); break;
  case LanguageItalian : ETrace::Do( _T("La langue italienne est sélectionnée.\n\n") ); break;
  case LanguageGerman : ETrace::Do( _T("La langue allemande est sélectionnée.\n\n") ); break;
  case LanguageSpanish : ETrace::Do( _T("La langue espagnole est sélectionnée.\n\n") ); break;
  }

eValConfig.MaskSuppressAdd( LanguageAll, LanguageFrench );

eValConfig.TraceEx();

// Seconde façon de déterminer la langue à utiliser
long lLanguageToUse = eValConfig.MaskGet( LanguageAll );

if ( lLanguageToUse == LanguageEnglish ) ETrace::Do( _T("La langue anglaise est sélectionnée.\n") );
if ( lLanguageToUse == LanguageFrench ) ETrace::Do( _T("La langue française est sélectionnée.\n") );
if ( lLanguageToUse == LanguageItalian ) ETrace::Do( _T("La langue italienne est sélectionnée.\n") );
if ( lLanguageToUse == LanguageGerman ) ETrace::Do( _T("La langue allemande est sélectionnée.\n") );
if ( lLanguageToUse == LanguageSpanish ) ETrace::Do( _T("La langue espagnole est sélectionnée.\n") );

Sortie :

### Object EValue Trace #
# Object address='0x0012F483', size of='1' byte(s) ('8' bits).
# Value:
# Decimal='43'(signed) '43'(unsigned), Hexadecimal='0x2B'.
# Binary = 00101011
# Equal. = ========
# Pos maj= 00000000
# Pos min= 76543210
### End #

La langue italienne est sélectionnée.

### Object EValue Trace #
# Object address='0x0012F483', size of='1' byte(s) ('8' bits).
# Value:
# Decimal='27'(signed) '27'(unsigned), Hexadecimal='0x1B'.
# Binary = 00011011
# Equal. = ========
# Pos maj= 00000000
# Pos min= 76543210
### End #

La langue française est sélectionnée.

Vue :

07 06 05 04 03 02 01 00

Champs de bits

0 0 1 0 1 0 1 1 Valeur originale
0 0 0 0 0 0 0 [1] TipAtStart
0 0 0 0 0 0 [1] 0 PrgCloseMessage
0 0 0 0 0 [1] 0 0 WindowOnTop
0 0 0 0 [1] 0 0 0 WindowShadow
0 [0 1 0] 0 0 0 0 LanguageItalian

07 06 05 04 03 02 01 00

Champs de bits

0 0 1 0 1 0 1 1 Valeur originale
0 0 0 0 0 0 0 [1] TipAtStart
0 0 0 0 0 0 [1] 0 PrgCloseMessage
0 0 0 0 0 [1] 0 0 WindowOnTop
0 0 0 0 [1] 0 0 0 WindowShadow
0 [0 0 1] 0 0 0 0 LanguageFrench

La déclaration de la variable occupe 1 octet (soit 8 bits). Comme on peut le constater 7 bits sont utilisés réellement (soit 87%), donc 1 bit est gaspillé.

L'économie par rapport à la première déclaration est de 19 octets sur 20 octets (soit 95%) et de 152 bits sur 160 bits.

Note

Certes l'utilisation poussée de l'objet EValue (étape 4) demande une rédaction plus rigoureuse (que l'étape 1) mais elle apporte beaucoup d'avantages :

1. Economie énorme de la mémoire. Imaginez cent mille structures initialisées par l'étape 1, cela demanderait près de 2 Mo de mémoire alors qu'avec l'étape 4 cela ne réclamerait que 100 Ko de mémoire.

2. Le processeur doit traiter ces données, plus il y de données et plus le système sera ralenti.

3. La sauvegarde de 2 Mo de données est plus lourde que la sauvegarde de 100 Ko que ce soit en terme de temps ou de place sur le disque dur (Non ?).

4. L'utilisation des opérateurs de bits par l'objet EValue ne réclame que très peu de temps au processeur car ces opérateurs font parties intégrante du langage machine, donc très rapides.