I - 2. Les variables en C++
A. Les variables et les données
a. Que ce qu"est une donnée ?
Comme pour la première question du premier cours, cette question peut paraître particulièrement débile. Cependant, vous l'aviez vous déjà posé ? Difficile de définir très précisément une donnée. Par définition, une donnée est une information connue qui sert de point de départ à un raisonnement, selon le Robert. Il peut s'agir d'un nombre de voitures sur une route, d'un nom de famille, d'une date... On peut donc conclure qu'une donnée est une valeur utilisable pour faire ce que l'on veut avec.
Dans le domaine électronique, comme vous le savez certainement, seul le binaire est utilisable, d'un point de vue physique. Donc, quelque soit votre donnée, elle sera représentée en binaire dans la mémoire de votre ordinateur. Je ne décrirai pas ici quel est la sorcellerie qui permet cela. Ce qui faut retenir, est que quel que soit la donnée électronique, elle a forcément une base en binaire. Nous verrons plus tard que ce qui permet d'utiliser correctement ces données pour pouvoir en faire ce que l'on veut.
Pour être stockées correctement, elles peuvent demander un certain nombre de 0 et de 1 différent, pour ne pas perdre de précision dans la valeur. Le nombre de 0 et de 1 nécessaire s'expriment généralement en octet (paquet de huits 0 ou 1). La quantité d'octet nécessaire pour une valeur est appelée le poids de la donnée. Par exemple, une données nécessitant 4 octets a un poids de 4 octets (logique).
Ces donneés ne sont cependant pas stockées dans la mémoire au hasard. On peut les retrouver dans la mémoire, grâce à quelque chose qui s'appelle leur adresse mémoire. Il s'agit, comme toutes les données numériques, d'un nombre binaire, qui permet de dérouler le chemin dans la mémoire de l'ordinateur jusqu'à la donnée souhaitée. Pour cela, l'ordinateur utilisent de complexes algorithmes, que nous ne détaillerons pas ici. Le plus important est de s'avoir que chaque donnée stockée sur mémoire à une adresse, permettant de la retrouver.
Une particularité de ces données est la façon dont on peut les modifier. En général, on peut modifier la valeur qu'elle contient, pour pouvoir opérer sur elle plus facilement avec un programme informatique. Si une donnée numérique peut changer de valeur, c'est une variable. Dans le cas contraire, c'est une constante. Bien que la majorité des données sont variables, il peut être intéressant de bien apprendre la différence entre les deux.
b. Qu'est ce qu'est une variable ?
Maintenant qu'on sait ce qu'est une variable, une donnée qui peut changer, on peut s'intéresser plus en détail à leur fonctionnement, qui les différe des données. En effet, cette petite particularité change beaucoup de choses, faisant la force de la programmation sur ordinateur.
La première chose à faire est de savoir bien distinguer plusieurs variables. En effet, comme nous l'avons vue, en tant que données, les variables possèdent elles aussi une adresse mémoire. Cette adresse mémoire n'est pas modifiable, mais seulement la valeur de la donnée stockée dans cette adresse mémoire. Il y a cependant quelques exceptions très spéciales que nous verrons après. De plus, utiliser chaque variable par leur adresse mémoire, comme "00111010100" ou "11000111000111", est aussi intuitif qu'appeler les gens par leur phénotype. Pour cela, dans la majorité des langages de programmation, elles sont utilisables via un nom, qui les relient à leur valeur en mémoire.
Il existe deux termes très impotant avec cette mécanique : la déclaration et la définition. IBM offre une approche intéressante de ces deux termes. La déclaration d'une variable est un concept fourbe, qui représente la création de l'ensemble de tout ce qui caractérise une variable, mais sans lui attribuer de valeur. En d'autre terme, c'est dire à l'ordinateur qu'une certaine variable existe quelque part, sans lui dire où. Ce concept n'est applicable qu'au moment de la programmation, est pas pendant l'exécution du programme. En général, c'est le linker qui s'occupe de dire où se trouve la variable, si elle existe. La définition représente le même concept, sauf qu'une partie de la mémoire est bel est bien utilisée pour stocker la valeur.
Pour économiser des la mémoire, ces variables doivent n'être définies que le temps où elles sont utiles. En général, leur adresse mémoire est en suite effacée des adresses à retenir, et donc la donnée est perdue, et est considérée "libérée". Cette zone de la mémoire peut être utilisée pour autre chose. Elle est cependant toujours accessible via des méthodes assez complexes, pouvant représenter une faille de sécurité. Le moment où la donnée est donc utilisable représente le temps de vie de son adresse mémoire, appelé sa portée.
c. Comment utiliser des variables ?
Une donnée inutilisée est, par définition, complétement inutile. Il faut donc utiliser les données disponibles, si on veut quelque chose qui sert à quelque chose. Cependant, l'utilisation des données est quelque chose de très vaste.
La première utilisation, évidente d'une donnée, est de la lire pour la modifier ou modifier une autre donnée selon cette donnée. Pour une constante, on ne peut cependant que modifier une autre donnée selon la valeur de la constante. En général, l'adresse mémoire de la variable est passée au processeur, pour en faire ce que vous voulez faire avec. Le processeur peut lire la valeur pour réaliser plusieurs types d'opérations. Par exemple, pour les processeurs sous format X86, une lecture possible est "AND", qui compare deux valeurs et remplace la valeur de la première par le résultat. Cependant, si la variable est seulement déclarée mais pas définie (voir les définitions en haut), le linker renvoie une erreur. La lecture est l'utilisation principale est la plus générale d'une variable.
Si la variable n'est pas constante, vous pouvez modifier sa valeur. C'est la deuxième utilisation la plus commune d'une variable. N'importe quelle valeur peut lui être attribué, que ce soit celle d'une autre variable ou une valeur inscrite dans le code source. D'un point de vue entièrement binaire et extrêmement bas niveau, les modifications applicables à la variables sont les instructions du processeur pouvant modifier sa valeur. Par exemple, pour les processeurs sous format X86, une modification possible est "ADD", qui additionne deux valeurs remplace la valeur de la première par le résultat. La modification de valeur est donc très importante pour pouvoir réaliser un programme cool.
Les plus attentifs d'entre vous ont dû remarquer quelque chose d'assez frustrant. En effet, les seules choses présentées ici vont dans le cas d'une utilisation de variables entièrement binaire. Cependant, si vous voulez faire un jeu 3D avec "AND" et "ADD", bonne chance. Bien évidemment, il est cependant possible de manipuler toutes les données imagineables avec seulement ces opérations, mais c'est très complexe. Heuresement, pour cela, il existe un paradigme de programmation permettant d'utiliser des normes d'utilisations très précises pour les données : la généricité. Ce système est plus connu comme le système définissant les normes d'utilisations par des types de variables.
Ces types représentant de simples normes, chaque langage a son propre système de typage. Par exemple, en Python, le système de typage est dynamique. Le type d'une variable peut changer pendant sa durée de vie. Cependant, certains langages, comme le C++, utilisent un système de typage statique. Le type d'une variable ne peut pas être modifié pendant sa durée de vie. Il y a cependant pleins de types possibles, présentés dans la prochaine partie.
B. Les types de variable en C++
a. Comment créer et utiliser une variable ?
En C++, il y a une quantité aberrante de façon de déclarer des variables. Cependant, pour ne pas perdre tout le monde, on va juste s'arrêter sur les méthodes de déclarations compatibles avec le premier programme C++, que nous avons fait au cours précédent. Pour l'instant, nous avons ce code la :
L'instruction pour déclarer une variable est assez simple. Voici la manière générale de déclarer une variable :
Il existe toute une convention de nommage pour les variables en C++. Cependant, il y a deux types de règles à respecter pour nommer des variables. Les premières sont les règles imposées par le compileur. Ces conventions sont écrites sur ce site web. Les principales choses à retenir sont qu'un nom de variable ne peut contenir que les 26 lettres de l'alphabet, des chiffres et des underscores "_". De plus, une variable ne peut que commencer par une lettre ou un underscore et ne doit pas avoir le même nom qu'un mot réservé (voir le site plus bas). Si une de ces conditions n'est pas respéctée, le programme plante. Les autres règles sont des conventions entre développeurs pour rentre le code plus lisible. Soyons honnête, il y a autant de façon de faire que de développeurs. L'objectif est que le nom soit simple, mais efficace et ordonné. N'hésitez pas à aller regarder des codes d'autres personnes, pour vous faire votre propre style.
Les variables ont bien d'autres utilisations que juste être rédéfinies sans modifications (heuresement). Ces utilisations sont toutes très précisément définies selon leur type. Pour savoir ce que l'ont peut faire avec les variables sans prise de tête, il est grandement conseillé de connaître ces types. Cependant, il existe 2 catégories de types. Les premiers sont les types fondamentaux, qui sont les types fondamentaux du C++, pas modifiables et présents dans tous les compilers C++. Les deuxièmes sont les types composés, qui sont fondamentaux pour certains, mais pas pour d'autres. Nous verrons dans la prochaine partie que les types fondamentaux, car les types composés pourraient occuper à eux tout seul plusieurs cours.
b. Les types fondamentaux numériques
Comme nous l'avons vus, pour déclarer une variable, il faut un nom de type connu. En C++, les types les plus primaires sont les types qui représentent des nombres entiers relatifs. Le type par excellence pour un entier relatif est "int". Pour notre exemple d'en haut, la définition juste serait :
Comme nous l'avons vus plus haut, chaque donnée en mémoire est stockée en binaire. Ces types sont eux aussi stockés en binaire. Cependant, le nombre en base binaire stocké en mémoire est exactement le nombre qu'on a donnée à la variable, en base 10. Le compiler se charge de la conversion de la base 10 au binaire par défaut, pour tous les nombres. Pour être plus précis, les nombres binaires sont stockées avec une technique nommé "le complément à 2". Cependant, les types "unsigned" utilisent la représentation direct du nombre qu'ils encodent en binaire, sans complément à 2. Si vous leur donnez un nombre négatif, il est fortement probable que la valeur devienne absolument aberrante, et il ne faut pas se faire avoir.
Comme avec n'importe quel nombre, il est possible de réaliser des calculs avec ces variables numériques très simplement. La façon la plus simple est d'utiliser les opérateurs. Pour faire une addition, il faut utiliser l'opérateur "+". Pour notre exemple de en haut, on peut faire :
Pour ceux qui n'ont pas de temps à perdre, il existe aussi d'autres opérateurs combinant opérateurs arithmétiques et opérateurs d'assignements. Ces opérateurs représentent les symboles de leur opérateur arithmétique suivi de "=". Par exemple, "+=" effectue directement une addition, "*=" une multiplication... Dans le cas de notre variable age, on peut faire :
Avec ces types en particulier, vous pouvez aussi manipuler la variable directement grâce au binaire. Pour cela, il faut utiliser des opérateurs binaires. Les opérateurs binaires les plus utiles sont l'inversion de bits "~", le AND binaire "&", le OR binaire "|", le XOR binaire "^", le décalage de bits vers la gauche "<<" et la droite ">>". Ils sont utilisables de la même façon que les opérateurs arithmétiques.
Cependant, si vous voulez utiliser des nombres décimaux plus complexes, ces types ne suffisent pas. Pour les nombres décimaux, il faut utiliser deux types : float (32 bits) ou double (64 bits). Les opérations binaires ne sont cependant pas accessibles avec eux. Appart cela, ils fonctionnent de la même façon que les types entiers, avec la possibilité de gérer des nombres décimaux. En C++, les nombres décimaux s'écrivent avec un ".", et pas un ",". Voici un exemple :
Après tout cela, ça serai bien de connaître la valeur d'une de ces variables. Pour cela, il faut utiliser une instruction, qui est déjà en partie présente dans le code :
c. Les autres types fondamentaux
Bien évidemment, il existe d'autres types fondamentaux en C++, bien que les types fondamentaux non décimaux sont assez peu utilisés. Un type assez étrange est le type "void". En effet, "void" veut dire pas de type, et peut sembler déroutant. D'ailleurs, il n'est pas possible de créer une variable de type "void". Cependant, ce type est utilisé par le compiler pour deux raisons. La première est qu'il permet de spécifier qu'une fonction en retourne pas de valeur (nous verrons ce que cela représente dans un prochain cours). La deuxième est qu'il permet de spécifier qu'un pointeur pointe vers un objet de n'importe quel type (nous verrons ce que cela représente dans un prochain cours). Au final, pour l'instant, il ne vous sera pas utile.
Un autre type qui sera très important dans les cours à venir est le type "bool". "bool" représente une condition, qui peut avoir pour réponse true (vrai) ou "false" (faux). Il est utile dans beaucoup de choses, que nous verrons après. En tous cas, si vous affichez son contenu avec "cout", vous obtiendrez 0 pour "false" et 1 pour "true".
Pour finir avec les types fondamentaux, il faut que je vous reparle d'un type qu'on a déjà vu : le type "char". En effet, je l'ai défini comme un type qui représente un nombre de 1 octet. Cependant, si vous exécutez cette instruction :
Cependant, de la même manière que nous avons utilisés "cout", nous pouvons utiliser un autre type nommé "string". "string" représente une chaîne de caractère très modulable et assez simple d'utilisation. Cependant, pour l'utiliser, il faut rajouter quelques instructions au début de notre code :
d. Les types composés
Par définition, les types composés sont des types composés d'autres types. D'un point de vue binaire, ils sont composés de valeurs binaires d'autres types, comme des "int", "string"... Dans ces types là, il y a 2 catégories différentes. La première est la catégorie des types composés fondamentaux. Ils sont crées directement par le compiler. L'autre catégorie est la catégorie des types définis par l'utilsiateur. En effet, il est possible de créer ses propres types, et nous verrons comment dans les prochains cours, car c'est la force même du C++.
Les 2 types les plus intéressants des types composés fondamentaux sont les pointeurs et les références. Il s'agit cependant d'un sujet très complexe, que je développerai en profondeur dans un prochain cours. En gros, ces 2 types représentent une adresse mémoire d'une autre variable, qui permet de l'utiliser "à distance". Le pointeur est beaucoup plus compliquée que la référence, donc je ne parlerai que de la référence pour l'instant. Une autre manière de définir la référence est de dire que c'est un moyen d'utiliser une variable, sans la redéfinir. Il faut ensuite définir la référence avec la variable à référencer. Pour définir une référence, il faut utiliser le symbole "&" à côté du type de la variable à référencer, comme cela :
Les 2 derniers types composés fondamentaux sont les fonctions et les listes. Comme pour les pointeurs, il s'agit de sujets très complets et complexes, que nous traiteront dans un prochain cours.
Pour finir avec les types, il faut aussi savoir qu'il est possible de créer ses propres types. Pour cela, il existe 2 systèmes principaux : les classes et les unions. Le système de classe est la raison de pourquoi le C++ est appelé un "langage orienté objet". Cependant, tout comme les pointeurs, fonctions et listes, nous reviendront dessus dans un prochaine cours. En effet, ce système permet de rendre le C++ infiniment modulable.
Annexes
Un petit truc en plus
Il y a des choses en C++ qu'il est difficile de rattacher à une catégorie particulière. À mon avis, les commentaires en sont le meilleur exemple. Un commentaire est un morceau de texte présent dans le code, mais qui sera ignoré par le compiler. L'idée est de pouvoir laisser des idées dans le code, sans que ça n'impact sans fonctionnement. En C++, pour une seule ligne, tout ce qui est après les symboles "//" sont des commentaires. Par exemple :
Sources
Voici une liste de sources qui m'ont permis d'écrire ce cours :
- Le site de C++ : CPlusPlus.com.
- Le site d'IBM : IBM.com.
- Le site du Larousse : Larousse.fr.
- Le site du Robet : LeRobert.com.