Vous êtes sur la page 1sur 12

Activité Pratique n° 2 (SMP S4, 2021-2022)

1. Création du fichier à inclure "smps4.hpp"


Le rôle de ce fichier est d'éviter d'avoir à Réecrire les directives d'inclusion au début de
chaque programme.
Dorénavant, nous nous contenterons d'une seule directive: #include "smps4.hpp"
Les guillemets qui délimitent le fichier à inclure, indique qu'il s'agit d'un fichier non
standard, et qui se trouve dans le même dossier que le programme qui l'utilise.

1 %%writefile smps4.hpp
2 #include <iostream>
3 #include <stdio.h>
4
5 #include <cmath>
6 #include <stdlib.h>
7
8 #include <limits.h>
9 #include <float.h>
10
11 using namespace std;

Writing smps4.hpp

Vérification

1 !ls -lt *.hpp

-rw-r--r-- 1 root root 138 Mar 25 11:31 smps4.hpp

1 !nl smps4.hpp

1 #include <iostream>
2 #include <stdio.h>

3 #include <cmath>
4 #include <stdlib.h>

5 #include <limits.h>
6 #include <float.h>

7 using namespace std;

2. Exemple de mauvais programme (bad programmers)


Avant de compiler et d'exécuter le programme suivant, essayer de:

expliquer pourquoi il est mauvais,


prévoir la sortie du programme et la noter sur papier.

Compiler et exécuter le programme puis comparer les résultats affichés avec les résultats
prévus.

1 %%writefile bad_program.cpp
2 //
3 #include "smps4.hpp"
4
5 int main () {
6 char c = 134;
7 int i = c, j = 0123;
8 float x = 1 / 3, y = 1.0 / 3;
9 cout << "i = " << i << endl
10 << "j = " << j << "\n"
11 << "x = " << x << endl
12 << "y = " << y << "\n";
13 return 0;
14 }

Writing bad_program.cpp

1 %%bash
2 g++ bad_program.cpp
3 ./a.out

i = -122
j = 83
x = 0
y = 0.333333

Rappel: les 6 nivaux d'apprentissage (par ordre de maîtrise croissant):


0. Acquésition et mémorisation de l'information
1. Compréhension
2. Application
3. Analyse des concepts
4. Evaluation des acquis
5. Création de nouveaux concepts ou produits.

La compréhension de ces erreurs nécessite le niveau d'apprentissage n° 4 (Analyse des


concepts acquis, compris et appliqués).

3. Types de données de base en C et C++


Taille mémoire des types de données de base

1 %%writefile taille_types_de_base.cpp
2 // Taille des types de base
3
4 #include "smps4.hpp"
5
6 int main() {
7 cout << " char: " << sizeof(char) << endl
8 << " wchar_t: " << sizeof(wchar_t) << endl
9 << endl;
10 cout << " short: " << sizeof(short) << endl
11 << " int: " << sizeof(int) << endl
12 << " long: " << sizeof(long) << endl
13 << " long long: " << sizeof(long long) << endl
14 << endl;
15 cout << " float: " << sizeof(float) << endl
16 << " double: " << sizeof(double) << endl
17 << " long double: " << sizeof(long double) << endl;
18 return 0;
19 }

Writing taille_types_de_base.cpp

1 !g++ taille_types_de_base.cpp

1 !./a.out

char: 1
wchar_t: 4

short: 2
int: 4
long: 8
long long: 8

float: 4
double: 8
long double: 16

4. Codage des entiers en RAM

5. Analyse de l'origine de la première erreur de bad_program.cpp


Le domaine de définition du type char est l'ensemble des 256 entiers compris entre -128
(ou 100000000 en binaire) et 127 (ou 11111111 en binaire),
La constanate 134 est de type int, et sa valeur binaire sur 8 bits est: 134 = 128 + 4 + 2 =
2^7 + 2^2 + 2^1 = 10000110,
Avant son affectation à c, cette valeur est d'abord convertie dans le type de c (char), qui
est signé et dont le codage en RAM se fait en binaire avec complément à 2
En binaire avec complément à deux, le code 10000110 est interprété comme le nombre
-128 + 4 +2 = -122, qui est la valeur affectée à la variable c.

Vérification de la cause de l'erreur 1 par analyse de la taille des types de


données utilisées.
1 %%writefile cause_erreur1.cpp
2 #include "smps4.hpp"
3
4 int main () {
5 char c = 134;
6 int i = c;
7 cout << " sizeof(134) = " << sizeof(134) << endl
8 << " sizeof(c) = " << sizeof(c) << endl
9 << " sizeof(int) = " << sizeof(int) << endl;
10 cout << " i = " << i << endl;
11 return 0;
12 }
13

Overwriting cause_erreur1.cpp

1 %%bash
2 g++ cause_erreur1.cpp
3 ./a.out

sizeof(134) = 4
sizeof(c) = 1
sizeof(int) = 4
i = -122

6. Codage en RAM des nombres réels: Algorithme de la virgule


floattante

Exemple de codage de réel


Voir diapos 19, 20, 21

7. Epsilon machine et précision des nombres réels


Propriétés importantes des nombres réels, qui dépendent de la machine et de son SE.
Elles sont définies dans des constantes prédédinies dans le fichier standard à inclure
float.h.
Les fichiers standards se céent par la procédure d'installation du compilateur dans des
répertoires standards.

1 %%writefile epsilon_machine.cpp
2 // Epsilon machine et précision des types réels
3
4 #include "smps4.hpp"
5
6 int main() {
7 cout << "Epsilon machine des types réels:" << endl
8 << " FLT_EPSILON: " << FLT_EPSILON << endl
9 << " DBL_EPSILON: " << DBL_EPSILON << endl
10 << " LDBL_EPSILON: " << LDBL_EPSILON << endl;
11 cout << "Précision des types réels:" << endl
12 << " FLT_DIG: " << FLT_DIG << endl
13 << " DBL_DIG: " << DBL_DIG << endl
14 << " LDBL_DIG: " << LDBL_DIG << endl;
15 return 0;
16 }

Writing epsilon_machine.cpp

1 %%bash
2 g++ epsilon_machine.cpp
3 ./a.out

Epsilon machine des types réels:


FLT_EPSILON: 1.19209e-07
DBL_EPSILON: 2.22045e-16
LDBL_EPSILON: 1.0842e-19
Précision des types réels:
FLT_DIG: 6
DBL_DIG: 15
LDBL_DIG: 18

8. Opérateurs C/C++
9. Conversions implicites de types
Se font selon des règles qui visent à éviter les pertes d'information.
Ne sont pas toujours possibles (cf. Messages d'erreur de type "can't convert ... into ...")

1 %%writefile type_conversions.cpp
2 #include "smps4.hpp"
3
4 int main() {
5 char c1, c2;
6
7 short s1, s2;
8
9 int i1, i2;
10
11 float x, y;
12
13 double z;
14
15 cout << "sizeof(char) = " << sizeof(char) << endl
16 << "sizeof(c1 + c2) = " << sizeof(c1 + c2)
17 << endl << endl;
18 cout << "sizeof(short) = " << sizeof(short) << endl
19 << "sizeof(s1 + s2) = " << sizeof(s1 + s2)
20 << endl << endl;
21 cout << "sizeof(int) = " << sizeof(int) << endl
22 << "sizeof(long) = " << sizeof(long) << endl
23 << "sizeof(i1 * i2) = " << sizeof(i1 * i2)
24 << endl << endl;
25 cout << "sizeof(float) = " << sizeof(float) << endl
26 << "sizeof(x / y) = " << sizeof(x / y) << endl
27 << "sizeof(double) = " << sizeof(double) << endl;
28 cout << "sizeof(z - x) = " << sizeof(z - x) << endl
29 << "sizeof(i1 + z) = " << sizeof(i1 + z) << endl
30 << "sizeof(z * z) = " << sizeof(z * z) << endl;
31 return 0;
32 }

Writing type_conversions.cpp

1 %%shell
2 g++ type_conversions.cpp
3 ./a.out

sizeof(char) = 1
sizeof(c1 + c2) = 4

sizeof(short) = 2
sizeof(s1 + s2) = 4

sizeof(int) = 4
sizeof(long) = 8
sizeof(i1 * i2) = 4

sizeof(float) = 4
sizeof(x / y) = 4
sizeof(double) = 8
sizeof(z - x) = 8
sizeof(i1 + z) = 8
sizeof(z * z) = 8

10. Analyse de l'erreur 2 de bad_program.cpp


L'erreur concerne le type de l'expression arithmétique 1/3, qui est déterminé en fonction de
ses deux opérandes 1 et 3.

1 %%writefile cause-erreur2.cpp
2 #include "smps4.hpp"
3
4 int main () {
5 float x = 1/3;
6 cout << "x = " << x << endl;
7 cout << "sizeof(1) = " << sizeof(1) << endl
8 << "sizeof(3) = " << sizeof(3) << endl
9 << "sizeof(1/3) = " << sizeof(1/3) << endl;
10 return 0;
11 }

Writing cause-erreur2.cpp

1 %%sh
2 g++ cause-erreur2.cpp
3 ./a.out
x = 0
sizeof(1) = 4
sizeof(3) = 4
sizeof(1/3) = 4

12. Règles de notation des constantes litérales (++)


Ces règles sont extrêmement simples, mais si elles ne sont pas bien rspectées elles
peuvent causer des erreurs extrêmemnt graves.

1 %%writefile constants_notations.cpp
2 #include "smps4.hpp"
3 int main() {
4 int a = 65, // décimal
5 b = 0101, // octal
6 c = 0x41; // hexadécimal
7 cout << "a = " << a << "\tsizeof(65) = " << sizeof(65) << endl
8 << "b = " << b << "\tsizeof(0101) = " << sizeof(0101) << endl
9 << "c = " << c << "\tsizeof(0x41) = " << sizeof(0x41) << endl;
10 float x = 1/3, // type de 1/3: int
11 y = 1.0/3, // type de 1.0/3: double
12 z = 1.0F/3; // type de 1.0F/3: float
13 cout << "x = " << x << "\tsizeof(1/3) = " << sizeof(1/3) << endl
14 << "y = " << y << "\tsizeof(1.0/3) = " << sizeof(1.0/3) << endl
15 << "z = " << z << "\tsizeof(1.0F/3) = " << sizeof(1.0F/3) << endl;
16 return 0;
17 }

Writing constants_notations.cpp

1 %%shell
2 g++ constants_notations.cpp
3 ./a.out

a = 65 sizeof(65) = 4
b = 65 sizeof(0101) = 4
c = 65 sizeof(0x41) = 4
x = 0 sizeof(1/3) = 4
y = 0.333333 sizeof(1.0/3) = 8
z = 0.333333 sizeof(1.0F/3) = 4

13. Cas des constantes de types caractère


Les caractères sont des cas particuliers d'entiers.
Leur particularité c'est que ce sont des nombres qui codent les différents symboles
(caractères).
Ces nombres sont nécessairement non signés, et sont donc codés selon le format binaire
pur, pour lequel il n'y a pas de bit de signe.
Pour les humains, les valeurs de ces codes peuvent être écrites de 4 façons différentes:
en ASCII
en décimal (base 10)
en octal (base 8), et
en héxadécimal (base 16)

1 %%writefile char_notations.cpp
2 // Notations de constantes de type char
3 #include "smps4.hpp"
4 int main() {
5 char c1 = 'A', // Ascii
6 c2 = '\101', // Octal
7 c3 = '\x41', // Hexadécimal
8 c4 = 65; // OK, mais type de 65: int
9 cout << "c1 = " << c1 << endl
10 << "c2 = " << c2 << endl
11 << "c3 = " << c3 << endl
12 << "c4 = " << c4 << endl;
13 return 0;
14 }
15

Writing char_notations.cpp

1 %%shell
2 g++ char_notations.cpp
3 ./a.out

c1 = A
c2 = A
c3 = A
c4 = A

14. Conversion explicites de types de données.


Explicite veut dire à la demande du programmeur, qui force la conversion souhaitée grâce
à un simple opérateur, qui s'utilise selon une simple syntaxe.

1 %%writefile casting.cpp
2 // Changement explicite de type
3 #include "smps4.hpp"
4
5 int main() {
6 cout << "1/3 = " << 1/3 << endl
7 << "(float)1/3 = " << (float)1/3 << endl
8 << "(float)(1/3) = " << (float)(1/3) << endl;
9 char c1 = 'a', c2 = '\t', c3 = '\n';
10 cout << "code de c1 = " << (int)c1 << endl
11 << "code de c2 = " << (int)c2 << endl
12 << "code de c3 = " << (int)c3 << endl;
13 return 0;
14 }

Writing casting.cpp

1 %%shell
2 g++ casting.cpp
3 ./a.out

1/3 = 0
(float)1/3 = 0.333333
(float)(1/3) = 0
code de c1 = 97
code de c2 = 9
code de c3 = 10

15. Exercices obligatoires (TP2)


En utilisant les constantes prédéfinies dans les fichiers à inclure standard limits.h et float,
déterminer pour au moins deux machines différentes et deux SE différents les bornes des
intervalles des valeurs possibles pour les différents types de base C/C++.
Analyser les résultas obtenus.
En utilisant vos propres mots écrire un paragraphe expliquant l'importance du choix du bon
type pour chaque donnée, y compris les constantes, et le risque que l'on coure si on
néglige ce choix.

1
check 0 s terminée à 12:49

Vous aimerez peut-être aussi