M1103—Cours de C++ (2)
Alain Casali
Marc Laporte
Plan
A. Les types caractères
B. Transtypage
C. Macros
D. Alias
E. Conversion
A. Les types caractères
Il y a plusieurs types de caractères "simples" :
codés (stockés) sur 1 octet = 8 bits : code ASCII
8 bits = 28 possibilités = 256 caractères au maximum
128 caractères de base code ASCII de base
128 caractères supplémentaires code ASCII étendu
codés sur 2 octets (16 bits) : code Unicode
16 bits = 216 possibilités = 65536 caractères au maximum
binaire décimal
0000 0000 0
... ...
0000 1001 9 caractère TAB (TABulation) '\t'
0000 1010 10 caractère LF (Line Feed) et NL (New Line) '\n'
... ...
0001 1111 31 caractère CR (Carriage Return) '\r'
0010 0000 32 espace 0100 0001 65 'A'
'!'
caractères ASCII
0010 0001 33 0100 0010 66 'B'
0010 0010 34 '"' 0100 0011 67 'C'
éditables
... ... ...
0011 0000 48 '0' 0110 0001 97 'a'
0011 0001 49 '1' 0110 0010 98 'b'
0011 0010 50 '2' 0110 0011 99 'c'
... ... ... ... ... ...
pas de caractère accentué dans le code ASCII de base
Il y a trois types de caractères "simples" codés sur 1 octet
char unsigned char signed char
Nous n'utiliserons pour commencer que le type char
cout << sizeof (char); 1 octet de 8 bits
En C++, les caractères, quel que soit leur type, sont des valeurs entières
il existe une relation d'ordre
on peut faire des opérations arithmétiques dessus
char Carac = 'A';
Carac "vaut" 65 (code ASCII de A)
cout << Carac; affichage de A car
l'injecteur << "sait bien" que c'est le symbole A que
l'utilisateur veut voir apparaître !
Carac = 65;
cout << Carac; affichage de A
Carac = 0x41;
cout << Carac; affichage de A
cout << Carac + 1; affichage de 66
Carac = Carac + 1; 97
cout << Carac; affichage de B
65
const char KShift = 'a' - 'A';
Carac = 'C';
cout << Carac + KShift; affichage de 99
Carac = Carac + KShift;
cout << Carac; affichage de c
Plan
A. Les types caractères
B. Transtypage
C. Macros
D. Alias
E. Conversion
B. Transtypage
B.1 Définition
"Conversion" d’ une valeur d'un type (source) dans un autre (cible).
B.2 Déclaration
TypeCible (ValeurDuTypeSource);
Exemple :
Carac = 'C';
cout << Carac + KShift << endl 99
<< int (Carac + KShift) << endl 99
<< char (Carac + KShift) << endl;c
Exemple : Initialisation d’une string contenant toutes les minuscules
string Minusc;
for (unsigned i (0); i < 26; i = i +1)
{
Minusc = Minusc + char ('a' + i);
}
cout << Minusc << endl; abcdefg...
Transtypage explicit
Exemple : Affichage des codes ACSII d’une string
Transtypage implicite
for (unsigned Val : Minusc)
{
cout << Val << '/'; 97/98/99/100/101/102/103/…
}
B.3 Transtypage implicite impossible
for (int i (0); i < [Link] (); i = i + 1)
{
cout << Minusc [i];
}
warning: comparison between signed and unsigned integer
expressions
Solution : utiliser un transtypage explicit
for (int i (0); i < int ([Link] ()); i = i + 1)
{
cout << Minusc [i];
}
ou
for (int i (0); unsigned (i) < [Link] (); i = i + 1)
{
cout << Minusc [i];
}
Ou encore mieux :
for (unsigned i (0); i < [Link] (); i = i + 1)
{
cout << Minusc [i];
}
Pourquoi s’embêter à faire des transtypages.
Plan
A. Les types caractères
B. Transtypage
C. Macros
D. Alias
E. Conversion
C. Les macros
c.1 "définition de type" directives destinées au préprocesseur
#define PETIT_ENTIER_T short Pas de ‘;’
Identificateur de la macro
Souvent en majuscules Texte équivalent
Directive du préprocesseur
Macro Texte équivalent
PETIT_ENTIER_T short
C.2 utilisation
Préprocesseur
PETIT_ENTIER_T Var; short Var;
Aussi appelée "macro" (instruction)
ENORMEMENT utilisé en langage C à connaître
suite du programme
#undef PETIT_ENTIER_T
...
PETIT_ENTIER_T Var2; Erreur de syntaxe :
PETIT_ENTIER_T n'existe plus
et peut être redéfini par n'importe quoi
#define PETIT_ENTIER_T "Bonjour"
...
cout << PETIT_ENTIER_T << endl; Préprocesseur
cout << "Bonjour" << endl; Ca
Camarche
marche......
mais
maisc'est
c'estidiot
idiot!!!
!!!
mauvaise utilisation de #define : préférer
typedef short PetitEntier_t;
C.3 "complément" du langage
exemple
#define Begin { pour les nostalgiques du Pascal
#define End }
// ...
for ( ; ; )
Begin mais sans aucun intérêt !!!
Instructions;
End
autre exemple
#define classdef typedef en minuscules !!!
C.4 Compilation conditionnelle
exemple
#defineDEBUG
#undef DEBUG
/* * /
*/ #ifdef DEBUG
... ...
instructions_1; instructions_1;
/* */ #endif /* DEBUG */
instructions_2; instructions_2;
/* * /
*/ #ifdef DEBUG
... ...
instructions_3; instructions_3;
/* */ #endif /* DEBUG */
C.5 - Raccourci d'écriture
"la constante npos de la classe string de l'espace de noms std"
#include <string>
using namespace std;
...
std::string::npos)
if ([Link] ("bidule")== string::npos)
...
mais si la clause using namespace std; interdite :
ou, plus lisible :
#define STRING std::string
...
if ([Link] ("bidule") == STRING::npos)
...
#undef STRING ne pas oublier
Plan
A. Les types caractères
B. Transtypage
C. Macros
D. Alias
E. Conversion
D. Les alias
D.1 A quoi ça sert?
• Faciliter la lecture du code;
• Simplifier l’écriture du code;
• Ajouter de la sémantique au code;
• Faire des conversions / transtypage impossible
D.2 Rappel sur les types
réserver le mot type pour les types de base (Plain Old Data)
types qui ont leur équivalence en C
identificateurs simples : int, long, ...
identificateurs composés : unsigned int, short int,...
mais aussi
tableaux (de n'importe quoi) : [] struct, union
D.3 Qu’est ce qu’un type?
ensemble de valeurs possibles
opérations de base (arithmétiques, bit à bit, décalages, booléennes
mais aussi [] et d'autres opérations sur les struct)
PAS DE FONCTIONS-MEMBRES
int Tab [] = {1, 2, 3};
[Link](); N'existe malheureusement pas !!
D.4 Alias sur un type
utiliser typedef pour "définir" un nouveau type
Définition :
typedef OldType NewType;
Exemple :
suffixe facultatif - obligatoire !!!
type muet
unsigned int UInt;
typedef unsigned int UInt_t ;
UInt_t UInt;
type nommé
D.5 Conversion / Transtypage (rappel)
Définition :
TypeCible (ValeurDuTypeSource);
Exemple :
int i = - 1;
cout << unsigned int (-1);
Le compilateur dit :
[Link]:YYY:10: error: expected primary-expression before
'unsigned’ cout << unsigned int (-1);
Le TypeCible ne doit pas contenir d’espace
Solution : utiliser un typedef
D.6 Et les classes dans tout ça?
réserver le mot classe pour le reste :
classes standard comme par exemple array, string, vector, etc.
classes "issues" des classes de base
- par dérivation étudié plus tard
- par instanciation de classes génériques
vector <int> VInt;
vector <string> VStr;
types muets
préférer classdef pour les classes
classdef vector <int> CVInt;
type nommé
et classes de l'utilisateur
Exemple : Définition d’une matrice
Sans les alias :
vector <vector<unsigned> > M (10);
Avec les alias :
classdef vector <unsigned> CVLine;
classdef vector <CVLine> CMatrix;
CMatrix M (10);
D.7 Avantages 1. Sémantique et lisibilité
2. Maintenabilité
for (CVLine & Line : M)
[Link] (10); Supposons qu’on souhaite
changer le type d’une cellule :
for (vector <short> & Line : M) unsigned -> int
[Link] (10);
Il faut parcourir tout le code et faire les changements.
Gros risque d’oublis => tests de non régression non
satisfaits
Plan
A. Les types caractères
B. Transtypage
C. Macros
D. Alias
E. Conversion
E. Conversion C++11
Pour convertir une string vers un int on utilise la fonction stoi ()
de profil :
int stoi (string, unsigned*, int)
1er paramètre : la chaine a convertir
2ème paramètre : un pointeur (=> nullptr, par défaut nullptr)
3ème paramètre : la base utilisée pour la conversion (par défaut 10)
Exemple :
string str1 = "10";
string str2 = "3.14159";
string str3 = "10xyz";
cout << stoi (str1) << ' ' 10
<< stoi (str2) << ' ' 3
<< stoi (str3) ; 10
cout << stoi (”10”, nullptr, 2); 2
Sur le même profil, on trouve les fonctions :
Nom Type de retour
stol() long
stoll () long long
stoul () unsigned long
stoull () unsigned long long
stof () float
stod () double
stold () long double
La string passée en paramètre ne doit pas contenir
d’erreur
Exemple :
string str4 = "xyz10";
int myint4 = std::stoi(str4);
terminate called after throwing an instance of
'std::invalid_argument'
what(): stoi
Abort trap: 6
La base doit être compatible avec la chaine à extraire
Exemple :
string str5 = "42";
int myint5 = stoi(str5, nullptr, 2);
terminate called after throwing an instance of
'std::invalid_argument'
what(): stoi
Abort trap: 6
On peut convertir n’importe quel type « intégral » en string en
utilisant un des fonctions to_string () de profil :
string to_string (int val);
string to_string (long val);
string to_string (long long val);
string to_string (unsigned val);
string to_string (unsigned long val);
string to_string (unsigned long long val);
string to_string (float val);
string to_string (double val);
string to_string (long double val);
int x;
cin >> x;
cout << "le chiffre contient " << to_string (x).size () << "
caractère(s)" << endl;
12345
le chiffre contient 5 caractère(s)