À QUOI ÇA SERT ?
Un programme manipule des données.
Une variable permet de stocker une donnée avec :
- un type ;
- un nom ;
- une valeur ;
- une durée de vie ;
- une adresse potentielle en mémoire.
Code: Select all
int age{23};
- int = type ;
- age = nom ;
- 23 = valeur.
1. POURQUOI LES TYPES EXISTENT
Prenons quatre octets :
Code: Select all
00 00 80 3F
- un entier ;
- un flottant ;
- plusieurs caractères ;
- des flags.
Le compilateur utilise aussi le type pour savoir :
- combien d’octets lire ;
- quelles instructions produire ;
- quelles opérations autoriser ;
- quel alignement utiliser.
2. INITIALISATION
Ancienne syntaxe :
Code: Select all
int x = 42;
Code: Select all
int x(42);
Code: Select all
int x{42};
Code: Select all
int x{};
Pourquoi utiliser {} ?
Parce que les accolades évitent plusieurs conversions dangereuses.
3. NARROWING
Exemple :
Code: Select all
double d{3.14};
int x = d;
La partie décimale est perdue.
Avec :
Code: Select all
int x{d};
Donc les accolades aident à détecter des pertes d’information.
En système cela compte énormément.
Exemple :
Tu as une taille sur 64 bits :
Code: Select all
std::uint64_t size = 0x100000000ULL;
Code: Select all
std::uint32_t small = size;
Pour une taille de buffer, cela peut devenir une vulnérabilité.
4. TYPES ENTIERS
C++ fournit :
Code: Select all
short
int
long
long long
Important :
La taille exacte n’est pas universelle.
Ne pense jamais :
"long = forcément 64 bits".
Sous Windows x64, long reste généralement 32 bits.
Un pointeur est 64 bits.
C’est le modèle LLP64.
Sous de nombreux Unix 64 bits, long est souvent 64 bits.
C’est le modèle LP64.
Donc :
Code: Select all
sizeof(long)
5. TYPES DE LARGEUR FIXE
Pour le bas niveau :
Code: Select all
#include <cstdint>
std::uint8_t
std::uint16_t
std::uint32_t
std::uint64_t
std::int8_t
std::int16_t
std::int32_t
std::int64_t
Imagine un format réseau :
Code: Select all
struct Header
{
std::uint16_t type;
std::uint32_t size;
};
Même chose pour :
- formats de fichiers ;
- registres ;
- structures partagées ;
- protocoles réseau.
6. signed ET unsigned
signed peut contenir des valeurs négatives.
Code: Select all
int x{-1};
Code: Select all
unsigned int x{42};
Code: Select all
int a{-1};
unsigned int b{1};
if (a < b)
{
}
-1 devient alors une énorme valeur positive modulo 2^N.
Donc la condition peut donner un résultat surprenant.
7. bool
Code: Select all
bool running{true};
bool failed{false};
À représenter un état logique.
Exemple :
Code: Select all
if (running)
{
...
}
8. char
Code: Select all
char c{'A'};
Chaîne :
Code: Select all
const char* text{"Hello"};
Code: Select all
wchar_t
Code: Select all
L"Hello"
Code: Select all
CreateFileW(L"file.txt", ...);
9. TYPES FLOTTANTS
Code: Select all
float
double
long double
Code: Select all
double x{3.14};
Exemple classique :
Code: Select all
double x = 0.1 + 0.2;
Pourquoi ?
Parce que 0.1 n’a pas une représentation binaire finie exacte, comme 1/3 n’a pas une écriture décimale finie.
10. LITTÉRAUX
Un littéral est une valeur écrite directement dans le code.
Code: Select all
42
3.14
'A'
"Hello"
true
Code: Select all
42
0x2A
0b101010
052
Hexadécimal est extrêmement courant en système :
Code: Select all
0x1000
0xFF
0x80000000
Parce qu’un chiffre hexadécimal représente exactement 4 bits.
Exemple :
Code: Select all
0xFF = 11111111
11. SUFFIXES
Code: Select all
42u
42L
42LL
3.14f
3.14L
Exemple :
Code: Select all
auto x = 42u;
12. numeric_limits
Pour connaître les limites d’un type :
Code: Select all
#include <limits>
std::numeric_limits<int>::min()
std::numeric_limits<int>::max()
Parce que les types peuvent varier selon la plateforme.
13. sizeof
Code: Select all
sizeof(int)
sizeof(void*)
Sur un système x64 typique :
Code: Select all
sizeof(void*) == 8
Attention : cela ne veut pas dire que les 64 bits sont tous utilisés matériellement pour l’adresse.
14. alignof
Code: Select all
alignof(int)
Cela devient important pour :
- structures ;
- SIMD ;
- ABI ;
- performances ;
- accès matériels.
À RETENIR
Le type est le lien entre les bits en mémoire et leur signification.
Pour le bas niveau :
- surveille les tailles ;
- surveille signed/unsigned ;
- utilise <cstdint> quand la largeur compte ;
- évite les conversions silencieuses ;
- initialise toujours tes variables.
