• Aucun résultat trouvé

Définition de type structure

On constatera que les champs qui ne sont pas explicitement initialisés sont, encore une fois, initialisés à leur valeur nulle. De plus, comme le montre cet exemple, il n’est pas nécessaire de respecter l’ordre d’apparition des différents champs dans la déclaration de la structure pour leur initialisation.

Il est possible de mélanger les deux syntaxes. Dans ce cas, les valeurs pour lesquelles aucun nom de champ n’est donné seront affectées au champs suivants le dernier champ nommé. De plus, si plusieurs valeurs différentes sont affectées au même champ, seule la dernière valeur indiquée sera utilisée.

Cette syntaxe est également disponible pour l’initialisation des tableaux. Dans ce cas, on utilis-era les crochets directement, sans donner le nom du tableau (exactement comme l’initialisation des membres de la structure utilise directement le point, sans donner le nom de la structure en cours d’initialisation). On notera toutefois que cette syntaxe n’est pas disponible en C++. Avec ce langage, il est préférable d’utiliser la notion de classe et de définir un constructeur. Les notions de classe et de constructeur seront présentées plus en détails dans le Chapitre 8. C’est l’un des rares points syntaxiques où il y a incompatibilité entre le C et le C++.

3.1.6. Les alias de types

Le C/C++ dispose d’un mécanisme de création d’alias, ou de synonymes, des types complexes. Le mot clé à utiliser esttypedef. Sa syntaxe est la suivante :

typedef définition alias;

oùaliasest le nom que doit avoir le synonyme du type etdéfinitionest sa définition. Pour les tableaux, la syntaxe est particulière :

typedef type_tableau type[(taille)]([taille](...));

type_tableauest alors le type des éléments du tableau.

Exemple 3-9. Définition de type simple

typedef unsigned int mot;

mot est strictement équivalent à unsigned int.

Exemple 3-10. Définition de type tableau

typedef int tab[10];

tab est le synonyme de « tableau de 10 entiers ».

Exemple 3-11. Définition de type structure

typedef struct client {

unsigned int Age;

unsigned int Taille;

} Client;

Chapitre 3. Types avancés et classes de stockage

Client représente la structure client. Attention à ne pas confondre le nom de la structure (« struct client ») avec le nom de l’alias (« Client »).

Note : Pour comprendre la syntaxe detypedef, il suffit de raisonner de la manière suivante. Si l’on dispose d’une expression qui permet de déclarer une variable d’un type donné, alors il suffit de placer le mot clétypedefdevant cette expression pour faire en sorte que l’identificateur de la variable devienne un identificateur de type. Par exemple, si on supprime le mot clétypedefdans la déclaration du type Client ci-dessus, alors Client devient une variable dont le type est struct client.

Une fois ces définitions d’alias effectuées, on peut les utiliser comme n’importe quel type, puisqu’ils représentent des types :

unsigned int i = 2, j; /* Déclare deux unsigned int */

tab Tableau; /* Déclare un tableau de 10 entiers */

Client John; /* Déclare une structure client */

John.Age = 35; /* Initialise la variable John */

John.Taille = 175;

for (j=0; j<10; j = j+1) Tableau[j]=j; /* Initialise Tableau */

3.1.7. Transtypages

Il est parfois utile de changer le type d’une valeur. Considérons l’exemple suivant : la division de5par 2renvoie2. En effet,5/2fait appel à la division euclidienne. Comment faire pour obtenir le résultat avec un nombre réel ? Il faut faire5./2, car alors5.est un nombre flottant. Mais que faire quand on se trouve avec des variables entières (ietjpar exemple) ? Le compilateur signale une erreur aprèsi dans l’expressioni./j! Il faut changer le type de l’une des deux variables. Cette opération s’appelle le transtypage. On la réalise simplement en faisant précéder l’expression à transtyper du type désiré entouré de parenthèses :

(type) expression

Exemple 3-12. Transtypage en C

int i=5, j=2;

((float) i)/j

Dans cet exemple,iest transtypé en flottant avant la division. On obtient donc2.5.

Le transtypage C est tout puissant et peut être relativement dangereux. Le langage C++ fournit donc des opérateurs de transtypages plus spécifiques, qui permettent par exemple de conserver la constance des variables lors de leur transtypage. Ces opérateurs seront décrits dans la Section 10.2 du chapitre traitant de l’identification dynamique des types.

Chapitre 3. Types avancés et classes de stockage

3.2. Les classes de stockage

Les variables C/C++ peuvent être créées de différentes manières. Il est courant, selon la manière dont elles sont créées et la manière dont elles pourront être utilisées, de les classer en différentes catégories de variables. Les différents aspects que peuvent prendre les variables constituent ce que l’on appelle leur classe de stockage.

La classification la plus simple que l’on puisse faire des variables est la classification locale - globale.

Les variables globales sont déclarées en dehors de tout bloc d’instructions, dans la zone de décla-ration globale du programme. Les variables locales en revanche sont créées à l’intérieur d’un bloc d’instructions. Les variables locales et globales ont des durées de vie, des portées et des emplace-ments en mémoire différents.

La portée d’une variable est la zone du programme dans laquelle elle est accessible. La portée des variables globales est tout le programme, alors que la portée des variables locales est le bloc d’instructions dans lequel elles ont été créées.

La durée de vie d’une variable est le temps pendant lequel elle existe. Les variables globales sont créées au début du programme et détruites à la fin, leur durée de vie est donc celle du programme. En général, les variables locales ont une durée de vie qui va du moment où elles sont déclarées jusqu’à la sortie du bloc d’instructions dans lequel elles ont été déclarées. Cependant, il est possible de faire en sorte que les variables locales survivent à la sortie de ce bloc d’instructions. D’autre part, la portée d’une variable peut commencer avant sa durée de vie si cette variable est déclarée après le début du bloc d’instructions dans lequel elle est déclarée. La durée de vie n’est donc pas égale à la portée d’une variable.

La classe de stockage d’une variable permet de spécifier sa durée de vie et sa place en mémoire (sa portée est toujours le bloc dans lequel la variable est déclarée). Le C/C++ dispose d’un éventail de classes de stockage assez large et permet de spécifier le type de variable que l’on désire utiliser :

auto: la classe de stockage par défaut. Les variables ont pour portée le bloc d’instructions dans lequel elles ont été crées. Elles ne sont accessibles que dans ce bloc. Leur durée de vie est restreinte à ce bloc. Ce mot clé est facultatif, la classe de stockageautoétant la classe par défaut ;

static : cette classe de stockage permet de créer des variables dont la portée est le bloc d’instructions en cours, mais qui, contrairement aux variables auto, ne sont pas détruites lors de la sortie de ce bloc. À chaque fois que l’on rentre dans ce bloc d’instructions, les variables statiques existeront et auront pour valeurs celles qu’elles avaient avant que l’on quitte ce bloc.

Leur durée de vie est donc celle du programme, et elles conservent leurs valeurs. Un fichier peut être considéré comme un bloc. Ainsi, une variable statique d’un fichier ne peut pas être accédée à partir d’un autre fichier. Cela est utile en compilation séparée (voir plus loin) ;

register: cette classe de stockage permet de créer une variable dont l’emplacement se trouve dans un registre du microprocesseur. Il faut bien connaître le langage machine pour correctement utiliser cette classe de variable. En pratique, cette classe est très peu utilisée ;

volatile: cette classe de variable sert lors de la programmation système. Elle indique qu’une va-riable peut être modifiée en arrière-plan par un autre programme (par exemple par une interruption, par un thread, par un autre processus, par le système d’exploitation ou par un autre processeur dans une machine parallèle). Cela nécessite donc de recharger cette variable à chaque fois qu’on y fait référence dans un registre du processeur, et ce même si elle se trouve déjà dans un de ces registres (ce qui peut arriver si on a demandé au compilateur d’optimiser le programme) ;

extern: cette classe est utilisée pour signaler que la variable peut être définie dans un autre fichier.

Elle est utilisée dans le cadre de la compilation séparée (voir le Chapitre 6 pour plus de détails).

Chapitre 3. Types avancés et classes de stockage

Il existe également des modificateurs pouvant s’appliquer à une variable pour préciser sa constance :

const: ce mot clé est utilisé pour rendre le contenu d’une variable non modifiable. En quelque sorte, la variable devient ainsi une variable en lecture seule. Attention, une telle variable n’est pas forcément une constante : elle peut être modifiée soit par l’intermédiaire d’un autre identificateur, soit par une entité extérieure au programme (comme pour les variablesvolatile). Quand ce mot clé est appliqué à une structure, aucun des champs de la structure n’est accessible en écriture. Bien qu’il puisse paraître étrange de vouloir rendre « constante » une « variable », ce mot clé a une utilité. En particulier, il permet de faire du code plus sûr ;

mutable: disponible uniquement en C++, ce mot clé ne sert que pour les membres des structures.

Il permet de passer outre la constance éventuelle d’une structure pour ce membre. Ainsi, un champ de structure déclarémutablepeut être modifié même si la structure est déclaréeconst.

Pour déclarer une classe de stockage particulière, il suffit de faire précéder ou suivre le type de la variable par l’un des mots clésauto,static,register, etc. On n’a le droit de n’utiliser que les classes de stockage non contradictoires. Par exemple,registeretexternsont incompatibles, de même queregisteretvolatile, etconstetmutable. Par contre,staticetconst, de même queconstetvolatile, peuvent être utilisées simultanément.