Ceci est une ancienne révision du document !
Chapitre précédent | Sommaire principal | Chapitre suivant |
---|
Quand on a vue la logique booléenne, l'inverse d'un nombre s'écrit en 32 bits :
#include <iostream> int main() { std::cout << std::hex << std::showbase; std::cout << ~0b1 << std::endl; }
affiche :
0xfffffffe
32 bits = 4 octets = la taille de la variable en mémoire. A chaque fois que l'on écrit une variable de type int, le compilateur réserve 4 octets en mémoire pour stocker la valeur.
Pour connaître la taille d'un type ou d'une variable, utilisation de sizeof :
#include <iostream> #include <string> int main() { std::cout << "sizeof(int) = " << sizeof(int) << std::endl; std::cout << "sizeof(double) = " << sizeof(double) << std::endl; std::cout << "sizeof(bool) = " << sizeof(bool) << std::endl; std::cout << "sizeof(std::string) = " << sizeof(std::string) << std::endl; std::cout << "sizeof(char) = " << sizeof(char) << std::endl; }
affiche (sur Coliru, peut changer selon le système) :
sizeof(int) = 4 sizeof(double) = 8 sizeof(bool) = 1 sizeof(std::string) = 8 sizeof(char) = 1
Avec des variables :
#include <iostream> #include <string> int main() { int x { 123 }; double d { 12.34 }; bool b { true }; std::string s { "hello, world!" }; char c { 'a' }; std::cout << "sizeof(int) = " << sizeof(x) << std::endl; std::cout << "sizeof(double) = " << sizeof(d) << std::endl; std::cout << "sizeof(bool) = " << sizeof(b) << std::endl; std::cout << "sizeof(std::string) = " << sizeof(s) << std::endl; std::cout << "sizeof(char) = " << sizeof(c) << std::endl; }
affiche :
sizeof(int) = 4 sizeof(double) = 8 sizeof(bool) = 1 sizeof(std::string) = 8 sizeof(char) = 1
Problème : occupation mémoire parfois inutile. Par exemple, bool qui pourrait être représenté par 1 bit est représenté par 1 octet (8 bits). Si on a besoin de compter de 0 à 3, int sur 4 octets est trop gros (il faut que 2 bits pour cela : 0b00, 0b01, 0b10 et 0b11).
Possible de modifier les types de base en ajouter des modificateurs, de façon à réduire leurs taille en mémoire ou leur plage de valeur. Par exemple, pour modifier la taille : short, long, long long.
#include <iostream> int main() { std::cout << "sizeof(char) = " << sizeof(char) << std::endl; std::cout << "sizeof(short int) = " << sizeof(short int) << std::endl; std::cout << "sizeof(int) = " << sizeof(int) << std::endl; std::cout << "sizeof(long int) = " << sizeof(long int) << std::endl; std::cout << "sizeof(long long int) = " << sizeof(long long int) << std::endl; }
affiche :
sizeof(char) = 2 sizeof(short int) = 2 sizeof(int) = 4 sizeof(long int) = 8 sizeof(long long int) = 8
Remarque : char est en fait un entier sur 1 octet, affiché par cout comme un caractère, selon le code ASCII. Mais peut être manipulé comme un entier
Pour modifier le signe : signed (par défaut, pas nécessaire de la mettre) et unsigned (que des positifs)
#include <iostream> int main() { std::cout << "sizeof(char) = " << sizeof(char) << std::endl; std::cout << "sizeof(unsigned char) = " << sizeof(unsigned char) << std::endl; std::cout << "sizeof(short int) = " << sizeof(short int) << std::endl; std::cout << "sizeof(unsigned short int) = " << sizeof(unsigned short int) << std::endl; std::cout << "sizeof(int) = " << sizeof(int) << std::endl; std::cout << "sizeof(unsigned int) = " << sizeof(unsigned int) << std::endl; std::cout << "sizeof(long int) = " << sizeof(long int) << std::endl; std::cout << "sizeof(unsigned long int) = " << sizeof(unsigned long int) << std::endl; std::cout << "sizeof(long long int) = " << sizeof(long long int) << std::endl; std::cout << "sizeof(unsigned long long int) = " << sizeof(unsigned long long int) << std::endl; }
affiche
sizeof(char) = 1 sizeof(unsigned char) = 1 sizeof(short int) = 2 sizeof(unsigned short int) = 2 sizeof(int) = 4 sizeof(unsigned int) = 4 sizeof(long int) = 8 sizeof(unsigned long int) = 8 sizeof(long long int) = 8 sizeof(unsigned long long int) = 8
La différence est que le signed ira de -Max à +Max et que unsigned ira de 0 à 2*Max
En fait, dans la norme, pas de garantie sur la taille, juste des garantie sur l'ordre char < short < int < long < long long. ( Fixed width integer types ? )
Pour les nombres réels, un peu différent :
#include <iostream> int main() { std::cout << "sizeof(float) = " << sizeof(float) << std::endl; std::cout << "sizeof(double) = " << sizeof(double) << std::endl; std::cout << "sizeof(long double) = " << sizeof(long double) << std::endl; }
affiche :
sizeof(float) = 4 sizeof(double) = 8 sizeof(long double) = 16
Ici, les noms changent, pas simplement des modificateurs de type (pour des raisons historiques : au début, que les float - qui veut dire floattant, pour nombre à virgule flottante - puis ensuite les réels 2 fois plus gros que les floats = appelé double. Ensuite taille au dessus, choisit long comme pour les entier).
Par de modificateurs pour les autres types
digits ? digits10 ? max_digits10 ? radix ?
utiliation de u, ul, ull pour modifier une littérale entier et f et l pour une littérale réelle.
max, min, epsilon, etc
Partir d'un code simple :
int x {}; int y {}; int z {}; int a {}; int b {}; int c {};
On décide de changer d'avis et d'utiliser des réels. Nécessite de tout remplacer
double x {}; double y {}; double z {}; double a {}; double b {}; double c {};
Même problème que pour les variables : nécessite modification de plusieurs lignes, code non facilement maintenable, non respect qualité logiciel.
Pour éviter cela, définir un type, le nommer et l'utiliser.
using local_type = int; local_type x {}; local_type y {}; local_type z {}; local_type a {}; local_type b {}; local_type c {};
Pour changer de type, besoin que de changer une ligne. Code plus facilement maintenable
Nom des types = même règle que pour les noms des variables. Souvent, pour montrer que c'est un type, on ajoute _t
a la fin (C++, STL, boost) ou on commence par une majuscule (Qt)
sémantique simple : donner un sens aux types.
ex:
int temp1 { 12 }; // heure int temp2 { 40 }; // minutes temps1 + temps2; // n'a pas de sens
Nommer les types :
using heure = int; using minute = int; heure temp1 { 12 }; minute temp2 { 40 };
Le type exprimer à quoi il correspond, c'est plus précis que “int”. Mais pas suffisant, on peut toujours écrire :
temps1 + temps2; // n'a pas de sens
idéallement, faudrait que compilateur préviennent. Pourquoi fait-il pas ? Parce que “heure” et “minute” ont un sens pour lecteur. Mais pour compilateur, ce sont des int, donc pas d'interdiction d'addition. Sémantique incomplète
Dans la suite, apprendre à créer ses types et créer une sémantique (des “règles” d'utilisation).
représentation des nombres entier négatif
limitation de représentation d'un nombre “réel” par une représentation limité en mémoire
expression : de même type, notion de typage fort (on ne mélange pas les types). Mais conversion possible
limite des nombres réels
Chapitre précédent | Sommaire principal | Chapitre suivant |
---|