Introduction au langage C

Cours système d'exploitation by Guillaume Chanel, Jean-Luc Falcone and University of Geneva is licensed under CC BY-NC-SA 4.0

Généralités

Un bref historique

Développé par Dennis Ritchie, Bell Labs, entre 1969 et 1973. Intimement lié au développement d’UNIX:

  • C à été créer pour pallier aux limites des langages existants (BCPL, B) dans le développement d’UNIX.
  • A partir de 1972 le noyaux UNIX est développé en C

Ken Thompson (gauche), un des créateur d’UNIX et Dennis Ritchie (droite)

Brian W. Kernighan and Dennis M. Ritchie , The C Programming Language, Second Edition, Prentice Hall, Inc., 1988.
Première édition: le standard “K&R-C “

Norme ANSI

ANSI C: une norme qui garantie la portabilité:

  • Définie les types manipulables et les convention d’utilisation;
  • Définie les entêtes de fonctions et constantes de librairies standard;
  • Exemples:
    • math.h: fonctions mathématiques courantes (cos, exp, pow, ...)
    • stdio.h: fonctions d’entrée/sortie du system (printf, scanf, getc, ...)
    • stdlib.h: allocation et libération de mémoire (malloc, free, ...), control du processus en cours (exit, ...), ...

Norme ANSI

Année Nom(s) Addition(s) principales
1989 C89
1990 C90 ISO-9899:1990 Mineurs: C90 ≈ C89
1999 C99 ISO-9899:1999 Gestion de nouveau types (complexes, booleen, …), inline function, ...
2011 C11 ISO-9899:2011 Exécution de threads (default GCC ≈ gnu11)

Norme ANSI

Le C aujourd'hui

Beaucoup de code libre et ouvert est en C (maintenant en C++):

  • GTK+, boite à outils pour le développement d’IHM;
  • Glib, boite à outils variée (listes chainée, arbres, timer ...);
  • Qt, pour le développement d’applications et d’IHM multiplateformes;
  • Boost, boite à outil scientifique (traitement du signal, algèbre linéaire, ...).

Depuis sa création C est resté un langage populaire:

  • très utilisé pour le code embarqué et le temps réel, de moins en moins utilisés pour les IHM;
  • beaucoup de langages sont inspirés de C (C++, Java, C#, Objective C, PHP).

Les compilateurs

Les principaux compilateurs C:

  • GCC: nativement sous Linux et accessible sous Windows grâce à MinGW;
  • Microsoft Visual Studio, Borland C: sous Windows avec IDE (Integrated Developpement Environement);
  • TCC, LCC: compilateurs ANSI très simples (Linux + Windows).

Caractéristiques principales

Avantages

  • Langage de bas niveau proche du langage machine et du système

    • code rapide et efficace
    • accès à la représentation interne des informations
    • sous UNIX /Linux le langage C est proche du système et permet de faire des appels au noyaux directement
  • Langage de haut niveau

    • Indépendant de la machine (tant qu’il existe un compilateur C pour celle-ci)
    • Beaucoup de types de données sont disponibles (tableaux, structures,…)
    • La norme ANSI donne accès à des fonctions de plus haut niveau

Caractéristiques principales

Inconvénients

  • Inadapté au développent occasionnel ou pour le test rapide d’algorithmes

  • L’efficacité peut être au dépend de la compréhension → Ne pas hésiter à mettre des commentaires claire dans le code

  • Langage sans garde fou: indices des tableaux non contrôlés, il est possible de tenter un accès partout en mémoire → programmation défensive:

    • toujours se méfier du code que l’on croit correct, s’attendre au pire;
    • tester le résultat de tous les appels aux fonctions, penser à toutes les erreurs possibles.

Un premier programme en C

							#include <stdio.h>
#include <math.h>

#define PI 3.14159265359
		
double surface(float x) {
		return x * x * PI;
}

/* La fonction main est toujours la première fonction du programmes à être	
	appellée lors que l'execution*/	
int main(void) {
int input, i;

		//la fonction printf affiche quelque chose		
		printf("Veuillez entrer une valeur: ");
		scanf("%d", &input); //la fonction scanf lit l'entrée utilisateur
		for(i=1; i < input; i++)     {
			float per = surface(i);
			printf("Le resultat pour %d est: %f\n", i, per);
		}

		return 0;
	}

Contrôle du flot d'exécution

Structure conditionelles

Les branchements if

int a, b, c;
...
if((a < 0) || !((b == 2) && (c != 4))) {
	printf("La condition est validée\n");
}
else {
	printf("La condition n'est PAS validée\n");
}

Les boucles for

Les boucles for

//Calcul la somme des N premiers entiers
int value = 0;
for(int i=0; i < N; i++) {
	printf("Nouvelle itération de la boucle\n");
	value += i;
}

Les boucles while

La boucle while

//Calcul la somme des N premiers entiers
int value = 0;
int i = 0;
while(i < N) {
	value += i;
	printf("Nouvelle itération de la boucle: %d\n", i++);
}

La boucle do...while: le contenu est toujours exécuté au moins une fois

//Calcul la somme des N premiers entiers
int value = 0;
int i = 0;
do {
	value += i;
	printf("Nouvelle itération de la boucle: %d\n", ++i);
}
while(i < N);

Intéruption de boucles

Il est possible d’interrompre le déroulement d’une boucle (for, while, do/while) en utilisant les mots clefs:

  • continue: passe à l’itération suivante;
  • break: sort de la boucle.
//Calcul la somme des nombre impairs allant de 0 à N
value = 0;
i = 0;
while(1) {
	if(i > N)
	break;
	if(i % 2 == 0) {
	i++
	continue;
	}
	value += i;
	printf("Nouvelle itération de la boucle: %d\n", ++i);
}

Attention dans certains cas (cf. ci-dessus), l’utilisation de break et continue est à évitée car elle rend le code moins lisible.

Les fonctions

Une fonction est toujours déclarée avant son utilisation:

typeValeurRetour nomDeLaFonction(type1 param1, ..., typeN paramN)

Le mot clef return indique un point d’arrêt de la fonction ainsi que la valeur que la fonction doit retourner.

float pourcentage(int valeur, int centPourcent) {
					  return ((float) valeur/centPourcent)*100;
					}

Une fonction peu ne rien retourner:

void pourcentage(int valeur, int centPourcent) {
					  printf("%f", ((float) valeur/centPourcent)*100);
					}

Les fonctions

Il est possible de déclarer une fonction juste avec son entête:

  • évite d’organiser les fonctions suivant la position de leurs appels;
  • Sépare l’interface utilisateur de l’implémentation, un premier pas vers la création de librairies.
float pourcentage(int , int);//Déclaration de l’entête
int main(void) {
int a,b;
...
//Utilisation de la fonction sans implémentation connue
pourcentage(a,b)
return 0;
}
float pourcentage(int valeur, int centPourcent){
return ((float) valeur/centPourcent)*100;
}
float pourcentage(int , int);//Déclaration de l’entête
int main(void) {
int a,b;
...
//Utilisation de la fonction sans implémentation connue
pourcentage(a,b)
return 0;
}
float pourcentage(int valeur, int centPourcent){
return ((float) valeur/centPourcent)*100;
}
float pourcentage(int , int);//Déclaration de l’entête
int main(void) {
int a,b;
...
//Utilisation de la fonction sans implémentation connue
pourcentage(a,b)
return 0;
}
float pourcentage(int valeur, int centPourcent){
return ((float) valeur/centPourcent)*100;
}

Passage par adresse

En C les paramètres sont passés par valeur (pas de modification des variables entrées).

Il n’y a pas de passage par référence, on a recours au passage par adresse:

  • on déclare les paramètres de la fonction comme pointeurs et on les utilise comme tel avec le symbole *;
  • lors de l’appel à la fonction on passe l’adresse de la variable, symbole &.
/*********************************************************************************
					Calcul le pourcentage du nombre "valeur" par rapport à "centPoucent"
					IN:
					  valeur: contient la valeur a mettre en rapport pour le calcul
							  du pourcentage. Une fois la fonction exécutée valeur
							  contient le pourcentage.
					  centPourcent: valeur par rapport à laquelle le pourcentage est calculé
					OUT:
					  retourne -1 si une valeur d'entrée n'est pas valide, 0 sinon
					**********************************************************************************/
					int versPourcentage(float *valeur, float centPourcent) {
					if( (centPourcent > 0) && (*valeur >= 0) ) {
						*valeur = (*valeur / centPourcent)*100;
						return 0;
					}
					else
						return -1;
					}
/* Utilisation de la fonction */
					int main(void) {
					  int val = 30; ret;
					  if ( (ret = versPourcentage(&val, 100)) < 0 )
						return ret;
					  else
						return val;
					}