Cours du langage C les opérateurs de manipulation de bits, tutoriel & guide de travaux pratiques langage C en pdf.
Manipulation des flottants
Les nombres flottants
L’opérateur == est défini pour les nombres réels cependant, étant donné que cet opérateur ne fait qu’une comparaison bit à bit des valeurs comparées, il ne doit être utilisé que pour ce type de comparaison or ce n’est généralement pas ce que l’on souhaite faire. Pour tester l’égalité de deux réels, il faut calculer leur différence et voir si elle est assez petite (et assez petite est à définir par le programmeur !). En effet, les calculs avec les nombres réels ne se font pas toujours avec une précision infinie. Cela signifie qu’un calcul qui devrait donner pour résultat 0.0 par exemple peut ne pas retourner exactement 0.0 à cause des éventuelles pertes en précision qui ont pu avoir lieu lors des calculs.
Les sources présentées sur cette pages sont libres de droits, et vous pouvez les utiliser à votre convenance. Par contre la page de présentation de ces sources constitue une oeuvre intellectuelle protégée par les droits d’auteurs. Copyright © 2008 – Melem. Aucune reproduction, même partielle, ne peut être faite de ce site et de l’ensemble de son contenu : textes, documents, images, etc sans l’autorisation expresse de l’auteur. Sinon vous encourez selon la loi jusqu’à 3 ans de prison et jusqu’à 300 000 E de dommages et intérêts.
Concepts avancés du langage C par Jessee Michaël C. Edouard (Accueil) intermédiaires et c’est pourquoi, le programmeur doit toujours lui-même définir une certaine tolérance à l’erreur à chaque calcul utilisant les nombres réels.
La source de ce problème, c’est qu’il existe une infinité de nombres réels et l’ordinateur n’est bien entendu pas capable de pouvoir les représenter tous. En d’autres termes, l’ensemble des nombres représentables par l’ordinateur est discret et fini et non continu. La distance entre deux réels consécutifs de cet ensemble n’est cependant pas forcément constante. Il existe une macro définie dans float.h appelée DBL_EPSILON qui représente la plus petite valeur x de type double tel que 1.0 + x != 1.0. En d’autres termes, DBL_EPSILON est le réel tel que le successeur de 1.0 dans l’ensemble des nombres représentables par le système est 1.0 + DBL_EPSILON.
Donc comment choisir epsilon ? Tout dépend de l’ordre de grandeur des valeurs comparées et de la tolérance à l’erreur que l’on veut avoir. Il n’y a donc rien d’absolu (ou « d’universel ») que l’on peut affirmer sur ce sujet. Si les nombres comparés sont de l’ordre de l’unité (mais pas trop proches de zéro), on peut choisir un epsilon absolu. Si la distance entre les deux nombres (c’est-à-dire |x – y|) est inférieure à epsilon, alors on doit les considérer comme « égaux ». Dans les autres cas, il faut généralement être beaucoup moins tolérant (comparaison de nombres proches de zéro par exemple) ou beaucoup plus tolérant (comparaison de grands nombres). Il faut par exemple considerer un epsilon e tel que x est égal à y (on suppose que |x| < |y|) s’il existe un réel k tel que |k| < e et y = x + k.x. e est appelée erreur relative maximale autorisée. k est l’erreur relative qu’il y a entre x et y. L’avantage de cette méthode, c’est qu’elle choisit automatiquement le epsilon absolu qui va le mieux en fonction des nombres comparés. C’est donc cette méthode qui est utilisée dans la plupart des applications.
Voici une fonction qui permet de comparer deux réels avec deux epsilons spécifiés : le premier absolu et le deuxième relatif. Choisir 0 comme epsilon absolu pour l’ignorer (c’est-à-dire, comparer directement en utilisant le epsilon relatif).
Les fonctions mathématiques
Les fonctions mathématiques sont principalement déclarées dans math.h. Le type flottant utilisé par ces fonctions est le type double.
– Structures, unions et énumérations
Les structures
Une structure est une variable qui regroupe une ou plusieurs variables, non nécessairement de même type (contrairement aux tableaux), appelées champs. L’accès à un champ d’une structure se fait par l’intermédiaire de l’opérateur point. Par exemple :
struct {char nom[20]; int age;} marc, luc, jean;
…
strcpy(marc.nom, « Marc »);
marc.age = 24 ;
…
D’habitude on renomme tout d’abord une structure avant de l’utiliser. Par exemple :
typedef struct {char nom[20]; int age;} PERSONNE;
…
PERSONNE marc, luc, jean;
…
Une structure peut être également nommée. Par exemple :
struct personne_s {char nom[20]; int age;} marc, luc, jean;
Dans ce cas, marc, luc et jean sont de type struct personne_s. On aurait également pu écrire :
struct personne_s {
Les sources présentées sur cette pages sont libres de droits, et vous pouvez les utiliser à votre convenance. Par contre la page de présentation de ces sources constitue une oeuvre intellectuelle protégée par les droits d’auteurs. Copyright © 2008 – Melem. Aucune reproduction, même partielle, ne peut être faite de ce site et de l’ensemble de son contenu : textes, documents, images, etc sans l’autorisation expresse de l’auteur. Sinon vous encourez selon la loi jusqu’à 3 ans de prison et jusqu’à 300 000 E de dommages et intérêts.
char nom[20];
int age;
};
Puis :
struct personne_s marc, luc, jean;
Et bien entendu, du moment qu’une structure a été nommée, on peut très bien écrire :
typedef struct personne_s PERSONNE;
L’opérateur = (affectation) peut être utilisé avec des structures (pour copier une structure) mais dans la pratique on n’en a rarement besoin. En effet, puisque l’espace occupée en mémoire par une structure peut être gigantesque, copier une structure vers une autre pénalisera considérablement, non seulement en termes de performances mais aussi en termes de vitesse d’exécution (à cause du temps d’accès à une cellule mémoire). C’est pourquoi on utilise généralement des pointeurs pour manipuler les structures. L’opérateur -> permet d’accéder à un champ d’une structure via un pointeur. Par exemple :
#include <stdio.h>
#include <string.h>
struct personne_s {
char nom[20];
int age;
};
void affiche_personne(struct personne_s * p);
int main()
{
struct personne_s jean;
strcpy(jean.nom, « Jean »);
jean.age = 24;
affiche_personne(&jean);
return 0;
}
void affiche_personne(struct personne_s * p)
{
printf(« Nom : %s\n », p->nom);
printf(« Age : %d\n », p->age);
}
L’initialisation d’une structure se fait de la même manière que pour un tableau, avec les mêmes règles. Par exemple :
struct personne_s jean = {« Jean », 24};
Les unions
Une union est, en première approximation, une variable dont le type n’est pas figé (c’est-àdire une variable « caméléon »). En fait, une variable de type union est une variable composée de champs de types différents et non nécessairement de même taille, mais à la différence d’une structure, les champs d’une union partagent le même emplacement mémoire. Les unions permettent donc de faire une économie de mémoire. Du point de vue syntaxique, elles ressemblent beaucoup aux structures, il suffit de remplacer struct par union.
Le programme suivant montre un exemple d’utilisation de cette union, u, entre trois variables de types différents (n, x et p).
Les sources présentées sur cette pages sont libres de droits, et vous pouvez les utiliser à votre convenance. Par contre la page de présentation de ces sources constitue une oeuvre intellectuelle protégée par les droits d’auteurs. Copyright © 2008 – Melem. Aucune reproduction, même partielle, ne peut être faite de ce site et de l’ensemble de son contenu : textes, documents, images, etc sans l’autorisation expresse de l’auteur. Sinon vous encourez selon la loi jusqu’à 3 ans de prison et jusqu’à 300 000 E de dommages et intérêts.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
union trois_en_un {
int n;
double x;
char * p;
};
int main()
{
union trois_en_un u;
printf(« Entrez un entier : « );
scanf(« %d », &(u.n));
printf(« Vous avez entre : %d\n\n », u.n);
printf(« Entrez un nombre flottant : « );
scanf(« %lf », &(u.x));
printf(« Vous avez entre : %f\n\n », u.x);
u.p = malloc(20);
if (u.p != NULL)
{
strcpy(u.p, « Au revoir. »);
printf(« %s\n\n », u.p);
free(u.p);
}
return 0;
}
Puisque les champs d’une union utilisent le même espace mémoire, les unions sont également utilisées pour interpréter un même motif binaire dans différents contextes (par exemple pour interpréter le contenu d’une mémoire comme un flottant, ou comme un entier, …), mais cette pratique est généralement utilisée dans les programmes de très bas niveau plutôt que dans des programmes portables.
Les champs de bits
Le langage C permet de créer, à l’intérieur d’une structure, des données (champs) dont la taille est spécifiée en bits.
Ces champs doivent être de type entier. Par exemple :
struct {
unsigned a : 1;
unsigned b : 1;
unsigned c : 4;
unsigned d : 3;
} x;
Ici, on a une structure x composée de 4 champs tous de type unsigned int : a de taille = 1 bit, b de taille = 1 bit, c de taille = 4 bits, et d de taille = 3 bits. Cela ne signifie pas que la taille de x est de 9 bits mais au moins 9 bits. La taille d’une donnée est toujours un multiple entier d’un « octet ».
Les champs de bits peuvent être également utilisés, en faisant une union avec un autre type, dans des programmes dépendantes d’une plateforme particulière pour accéder directement aux bits d’une donnée quelconque. On retrouve alors l’intérêt de créer des champs sans noms : ils sont juste utilisés pour espacer des champs entre eux. Dans des programmes portables, on utilisera plutôt les opérateurs de manipulation de bits que les unions et les champs de bits. Attention ! Puisque les champs d’un champ de bits représentent des bits d’une variable et non des variables indépendantes, on ne peut pas leur appliquer l’opérateur & (adresse de). Mais il peut bien entendu être appliqué à la structure elle-même qui est une variable comme toutes les autres.
I – Compléments et rappels
I-A – Les différentes classes de variable
I-B – Les expression constantes
I-C – Initialisation des variables
I-D – Les déclarations complexes
II – Fonctions
II-A – Pointer sur une fonction
II-B – Point d’entrée d’un programme C
II-C – Quelques fonctions utiles
II-D – La récursivité
III – Manipulation des flottants
III-A – Les nombres flottants
III-B – Les fonctions mathématiques
IV – Les opérateurs de manipulation de bits
IV-A – Présentation
IV-B – L’opérateur ET (AND)
IV-C – L’opérateur OU (OR)
IV-D – L’opérateur OU EXCLUSIF (XOR)
IV-E – L’opérateur NON (NOT)
IV-F – L’opérateur de décalage vers la gauche (<<)
IV-G – L’opérateur de décalage vers la droite (>>)
IV-H – Autres opérateurs
V – Structures, unions et énumérations
V-A – Les structures
V-B – Les unions
V-C – Les champs de bits
V-D – Les énumérations
VI – Bibliothèque standard
VI-A – Fonctions à arguments en nombre variable
VI-B – Les paramètres régionaux
VI-C – « Type » des caractères
VI-D – Les caractères larges
VI-E – Recherche dans une chaîne
VI-F – Conversion des chaînes
VI-G – Fonctions de manipulation de chaîne « généralisées »
VI-H – La date et l’heure
VI-H-1 – Généralités
VI-H-2 – Connaître la date et l’heure courantes
VI-H-3 – Les conversions date <-> timestamp
VI-H-4 – Connaître le temps processeur d’un programme
VI-I – Les nombres pseudo-aléatoires
VII – Pour conclure
……….