Aller au contenu

Programmation C source/Classe de stockage

Un livre de Wikilivres.
Programmation C source
Programmation C++
Programmation C++
Sommaire
Modifier ce modèle
#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;
}