#include <stdio.h>
int main(void)
{
printf("------------------------------\n");
printf(" Classe de stockage\n");
printf("------------------------------\n");
/* auto : pour les variables locales, obsolète
extern : déclare une variable sans la définir
register : demande au compilateur de faire tout son possible
pour utiliser un registre processeur pour cette variable
static : rend une définition de variable persistante. */
/* Une variable, ou un paramètre de fonction,
ne peut avoir qu'au plus une classe de stockage */
printf("\n------------------------------\n");
printf(" Classe static\n");
printf("------------------------------\n");
void f(void)
{
static int i = 0;
/* i est de type static int
i ne sera initialisé à 0 qu'au premier appel de f */
int j = 0;
/* j est une variable standard
j sera initialisé à 0 chaque fois */
i++;
j++;
printf("i vaut %d et j vaut %d.\n", i, j);
}
f();
f();
f();
/* Objet local à une fonction :
la valeur de la variable sera persistante entre les différents appels
de la fonction. La variable ne sera visible que dans la fonction,
mais ne sera pas réinitialisée à chaque appel de la fonction. */
/* Objet global et fonction :
comme une variable globale est déjà persistante,
le mot-clé static aura pour effet de limiter la visibilité de la variable
ou de la fonction au seul fichier où elle est déclarée */
printf("\n------------------------------\n");
printf(" Classe extern\n");
printf("------------------------------\n");
#if 0
/* extern permet de déclarer une variable sans la définir.
la variable provient d'un autre fichier.
exemple */
// fichier1.c
int ma_variable_globale_externe;
// fichier2.c
extern int ma_variable_globale_externe;
// permet d'utiliser la variable de fichier1 dans fichier2
#endif
printf("\n------------------------------\n");
printf(" Classe register\n");
printf("------------------------------\n");
/* Indique que la variable devrait être stockée dans un registre du processeur
Cela permet de gagner en performance par rapport à des variables stockées
en mémoire vive.
Mais attention les registres du processeur sont limités, aussi bien en nombre
qu'en taille. Inutile de déclarer une structure entière ou un tableau avec
le mot clé register.
les variables placées dans des registres sont forcément locales à des fonctions ;
on ne peut pas définir une variable globale en tant que registre.
ce mot-clé est déconseillé sauf pour des cas particuliers, les compilateurs
modernes sachant généralement mieux que le programmeur comment optimiser et
quelles variables placer dans les registres. */
register short i, j;
for (i = 1; i < 3; ++i)
{
for(j = 1; j < 3; ++j)
{
printf("%d %d\n", i, j);
}
}
printf("\n------------------------------\n");
printf(" Classe auto\n");
printf("------------------------------\n");
/* Cette classe est un héritage du langage B.
Ce mot-clé sert pour les variables locales à une fonction non-statiques.
Mais une variable déclarée localement à une fonction sans qualificateur static
étant implicitement automatique, ce mot-clé est inutile */
printf("\n------------------------------\n");
printf(" Qualificateurs\n");
printf("------------------------------\n");
/* const : pour définir une variable dont la valeur ne devrait jamais changer
restrict : permet une optimisation pour la gestion des pointeurs
volatile : désigne une variable pouvant être modifiée notamment par une source
externe indépendante du programme.
Une variable, ou un paramètre de fonction, peut avoir aucun, un, deux, ou les
trois qualificateurs (certaines combinaisons n'auraient que peu de sens, mais sont
autorisées) */
printf("\n------------------------------\n");
printf(" Qualificateur const\n");
printf("------------------------------\n");
/* La classe const ne déclare pas une vraie constante, mais indique au compilateur
que la valeur de la variable ne doit pas changer. Il est donc impératif
d'assigner une valeur à la déclaration de la variable, sans quoi toute tentative
de modification ultérieure entrainera une erreur de la part du compilateur */
#if 0
const int i = 0;
i = 1; // erreur
/* Qu'est ce qu'un pointeur ?
Un pointeur a pour valeur l'adresse d'un objet C d'un type donné */
int i;
// la variable i en mémoire a une adresse
int * p = &i;
/* p a pour valeur l'adresse de i
on dit que p pointe sur i de type int */
// const indique ici qu'on ne modifie pas l'objet pointé
void fonction(const char * pointeur)
{
/* si pointeur = "une chaine de caractères"
pointeur[0] représente u le premier caractère */
pointeur[0] = 0; // erreur
pointeur = "Nouvelle chaine de caractères";
}
// const indique ici que la valeur(une adresse) elle-même du pointeur est constante
char * const pointeur = "Salut tout le monde !";
pointeur = "Hello world !"; // erreur
/* les deux à la fois
indique qu'on ne modifie pas l'objet pointé
et indique que la valeur(une adresse) elle-même du pointeur est constante */
const char * const pointeur = "Salut tout le monde !";
pointeur = "Hello world !"; // erreur
pointeur[0] = 0; // erreur
#endif
printf("\n------------------------------\n");
printf(" Qualificateur volatile\n");
printf("------------------------------\n");
/* Ce mot-clé sert à spécifier au compilateur que la variable peut être modifiée à
son insu. Cela annule toute optimisation que le compilateur pourrait faire, et
l'oblige à procéder à chaque lecture ou écriture dans une telle variable tel que
le programmeur l'a écrit dans le code.
Ceci a de multiples utilisations :
pour les coordonnées d'un pointeur de souris qui seraient modifiées par un autre
programme ;
pour la gestion des signaux (voir Gestion des signaux) ;
pour de la programmation avec de multiples fils d'exécution qui doivent
communiquer entre eux ;
pour désigner des registres matériels qui peuvent être accédés depuis un
programme C (une horloge, par exemple), mais dont la valeur peut changer
indépendamment du programme ; */
#if 0
// On peut combiner const et volatile dans certaines situations. Par exemple :
extern const volatile int horloge_temps_reel;
/* déclare une variable entière, qu'on ne peut modifier à partir du programme,
mais dont la valeur peut changer quand même, et qui provient d'un autre fichier.
Elle pourrait désigner une valeur incrémentée régulièrement par une horloge
interne. */
#endif
printf("\n------------------------------\n");
printf(" Qualificateur restrict\n");
printf("------------------------------\n");
/* Introduit par C99, ce mot-clé s'applique aux déclarations de pointeurs
uniquement. Avec restrict, le programmeur certifie au compilateur que le pointeur
déclaré sera le seul à pointer sur une zone mémoire. Cela permettra au
compilateur d'effectuer des optimisations qu'il n'aurait pas pu deviner
autrement. Le programmeur ne doit pas mentir sous peine de problèmes...
Par exemple : */
int * restrict pZone;
// cc -std=c99 -Wall 3classe.c -o 3classe
return 0;
}