Opérations bit à bit - pierre

Transcription

Opérations bit à bit - pierre
Programmation procédurale
Opérations bit à bit
NON
~
ET
&
OU
|
DROITE
>>
GAUCHE
<<
unsigned a
unsigned b
16bits) */
unsigned a
unsigned b
unsigned c
unsigned a
unsigned b
unsigned c
unsigned a
unsigned b
unsigned c
unsigned a
unsigned b
unsigned c
= 1;
/*
0000000000000001*/
= ~a; /* b = 1111111111111110 (en supposant sur
=
=
=
=
=
=
=
=
=
=
=
=
0xF0F0; /*
1111000011110000*/
0x00FF; /*
0000000011111111*/
a & b; /* c = 0000000011110000 soit 0x00F0 */
0xF0F0; /*
1111000011110000*/
0x00FF; /*
0000000011111111*/
a | b; /* c = 1111000011111111 soit 0xF0FF */
0xF0F0;
/*
1111000011110000*/
2;
a >> b; /* c = 0011110000111100 soit 0x3C3C */
0xF0F0;
/*
1111000011110000*/
2;
a << b; /* c = 1100001111000000 soit 0xC3C0 */
Exemple 1 : Convertir un nombre décimal en binaire
void en_binaireB(int deci) {
int masque = 1<<32-1; //En supposant 32bits
for(int i=0;i<32;i++){
printf("%d",(deci&masque)>>i); On va se servir d’un masque qui va changer
à chaque itération :
masque=masque>>1;
1000 0000 0000 0000 0000 0000 0000 0000
}
0100 0000 0000 0000 0000 0000 0000 0000
printf("\n");
etc…
}
Et afficher le résultat d’un ET bit à bit (soit
si pour le bit n on a 1 et 0 alors on affichera
0, si on avait eu 1 et 1 on aurait affiché 1).
Exemple 2 : On décide de définir un type abstrait de données permettant de représenter de
grands ensembles d'entiers (compris entre 0 et 999). Pour l'implémentation de ce type, on décide
de représenter un grand ensemble par un tableau de bits (si un nombre est présent dans
l'ensemble, le bit correspondant à ce nombre sera mis à 1, sinon le bit sera à 0).
#include <stdio.h>
#define CHAR_SIZE 8
/* nombre de bits dans un char */
#define MAX_BIGSET 125
/* nombre de cellules dans un ensemble */
#define MAX_VAL
(CHAR_SIZE * MAX_BIGSET)
typedef unsigned char BIGSET[MAX_BIGSET]; /*un ensemble dans [0..MAX_VAL[ */
void BIGSET_init(BIGSET s){ /* créer l'ensemble vide */
for(int i=0;i<MAX_BIGSET;i++){
s[i] = 0;
}
}
void BIGSET_add(BIGSET s, int i){ /* ajouter i dans s */
int index = i/CHAR_SIZE;
s[index] = s[index]|1<<(i%CHAR_SIZE);
}
int BIGSET_is_in(BIGSET s, int i){ /* 1 si i dans s et 0 sinon */
int index = i/CHAR_SIZE;
return (s[index]&1<<(i%CHAR_SIZE))? 1:0;
}
void BIGSET_print(BIGSET s){ /* afficher les éléments de s */
char m;
for(int y=0;y<MAX_BIGSET;y++){
m = 1;
for(int i=0;i<CHAR_SIZE;i++){
if(s[y]&m){
printf("%d ",i+(y*CHAR_SIZE));
}
m=m<<1;
}
}
}
void BIGSET_inter(BIGSET s1, BIGSET s2, BIGSET res){
for(int y=0;y<MAX_BIGSET;y++){
res[y]=s1[y]&s2[y];
}
}
int main(int argc, char *argv[]) {
BIGSET e1, e2, e3;
int i;
BIGSET_init(e1); BIGSET_init(e2);
for (i = 0; i < 40; i += 5) BIGSET_add(e2, i);
for (i = 0; i < 40; i += 3) BIGSET_add(e1, i);
BIGSET_inter(e1, e2, e3);
printf("e1 = "); BIGSET_print(e1); /* e1 = 0 3 6 9 12 15 18 21 24 27
30 33 36 39 */
printf("\ne2 = "); BIGSET_print(e2); // e2 = 0 5 10 15 20 25 30 35
printf("\ne3 = "); BIGSET_print(e3); // e3 = 0 15 30
printf("\n");
}
Opérateurs

Affectation (signe « = ») :
int i = 1;
i = i +1;
int i = 1;
i = i++;
int i = 1;
int i = 1;
 i +=1;
 i = ++i;
Dans le cas d’un affichage au même moment que l’affectation la valeur peut varier, cela va
dépendre du sens d’évaluation, exemple :

i = 3; j = 3;
printf("i = %d j = %d", i++, ++j);
/* 3 and 4 */
printf("i = %d j = %d", i, j); /* 4
and 4 */
i = 3; j = 3;
printf("i = %d j = %d", i++, ++j);
/* 4 and 3 */
printf("i = %d j = %d", i, j); /* 4
and 4 */
 Sizeof
L’opérateur sizeof() retourne la taille de l’objet fourni en argument.
sizeof, retourne la taille dans la mémoire d’un élément, on ne peut pas s’en servir pour
connaitre directement la taille d’un tableau passé en paramètre dans une fonction par exemple.
Exemple :
int i; char c;int tabi[10];char tabc[10];
printf("%ld %ld %ld %ld %ld \n",sizeof(i),sizeof(c),sizeof(tabi),sizeof(tabc),
sizeof(tabi)/sizeof(tabi[0])); //4 1 40 10 10

Conversion
Explicite
Implicite
printf("%d %f",(int) 2.0, (float)4); printf("%d", 'a');
//2 4.000000
//92
D’une manière générale pour convertir il faut que les types soient compatibles (et pour le faire
de manière implicite que le type cible “englobe” le type source).
 Condition ternaire
Syntaxe :
condition ? expression1: expression2
Exemple :
int min (int a, int b){
else return b;
return (a<b) ? a : b;
}
If(a<b)
(Then) return a ;
Ce genre de condition n’est pas adapté à toutes les situations.
 Opérateur virgule
Permet de mettre plusieurs instructions à la suite :
for (i=0,j=max; i<j; i++,j--) { //A chaque iteration change les deux indexs (i,j)
int tmp = t[i];
t[i] = t[j];
t[j] = tmp;
}
Énoncées
Une expression fournit une valeur alors qu’un énoncé change un état (effectue une action).
En C, toute expression peut devenir un énoncé si on ajoute « ; ».
Il est possible de créer des énoncés vides :
while ((c = getchar()) != ' ')
;

while ((c = getchar()) != ' ') {
}
Énoncé composé :
Ou bloc, permet de regrouper plusieurs énoncés, restreindre la visibilité d’une variable au
bloc où elle est déclarée et à dénoter le corps d'une fonction.
Il existe de nombreux énoncés : if, while, for, do, switch, break, continue, return.
- Différences entre while et do :
while (<expression logique>)
<enoncé>;
do
<énoncé>;
while (<expression logique>)
Peut ne jamais rentrer dans le bloc
Exécute le bloc au moins une fois
- Case (d’un switch) :
« Saute » directement au bon case et effectue toutes les énoncés jusqu’à rencontrer un
break ( sortie de bloc).
switch (c) { //Dans le cas où c
case 'a' : printf("Case a
case 'A' : printf("Case A
case 'b' : printf("Case b
case 'B' : printf("Case B
default : printf("DEFAULT
} //Affiche : Case A Case b
vaut ‘A’
");
");
");break;
");
Cas par défaut (si on entre
");
dans aucun autre case).
- L’énoncé continue permet de passer à l’itération suivante sans sortir du bloc
(contrairement au break ou à un return qui sort carrément de la fonction courante).