[Tutoriel] Introduction au Langage C

• Astuces et tutoriels sur les langages de programmation C et C++.

Modérateurs: Modérateurs(trices), Rédacteurs(trices) de Tutoriels

Règles du forum
Aucune demande de support n’est autorisée dans ces forums !

Messagepar DJ Kin-C » Ven 1 Juil 2011 11:26

Introduction au langage C



Sommaire

  1. Introduction
  2. Un langage compilé
  3. Les langages compilés
  4. Les langages interprétés
  5. Compilation d’un programme
  6. Détails des options
  7. Les bases du langage
    1. Les mots clés
    2. Les commentaires
    3. Structure générale d’un programme C
    4. Notion d’identification
    5. Notion de variable
    6. Les types primitifs
    7. Les entiers
    8. Représentation des valeurs
    9. Les caractères
    10. Les flottants
    11. Le type void
  8. La syntaxe du langage
    1. Notion d’expression
    2. Opérateurs arithmétiques
    3. Opérateurs d’affectation
    4. Opérateurs relationnels
    5. Opérateurs logiques
    6. Opérateurs bit à bit
  9. Les structures décisionnelles
    1. Instruction if
    2. Instruction Switch
    3. L’opérateur Ternaire


I- Introduction

Premier cours d’apprentissage au langage C.
Relation entre langage, programme et environnement d’exécution.

Informations :

  • Difficulté : Moyenne


II- Un langage compilé

Dans le domaine de l’information moderne, on utilise aujourd’hui principalement des langages de haut niveau, c’est à dire plus facilement compréhensible par l’homme, en opposition avec des langages de bas niveau, comme l’assembleur, plus facilement compréhensible par la machine.
Parmi ces langages, on distingue 2 grandes familles : les langages compilés et les langages interprétés.


III- Les langages compilés

Il s’agit des langages qui nécessites un étape de compilation unique pour pouvoir être ensuite exécutés et interprétés par le système. Parmi ces langages on peut citer le C, C++, Java, Pascal...
Étant donnée que la phase de compilation n’est réalisée qu’une seule fois, ce type de langage est plus adapté pour la réalisation d’applications plus efficaces ou de plus grande envergure. Par ailleurs, ils permettent un accès plus précis aux ressources du systèmes.


IV- Les langages interprétés

Dans ce cas, le programme est compilé et interprété à la volé à chaque fois qu’il est exécuté. Ces langages sont très adaptés pour le développement rapide d’applications, de prototypes, ou pour l’extension de programmes sous forme de plug-in. En revanche puisqu’ils doivent être compilés à la volé, puis interprétés, leur exécution est plus lente. Parmi ces langages on peut citer : Php, JavaScript, Perl ou encore Lua, Python...
Bien que très pratique, ces langages ne sont pas conseillés là ou les exigences non fonctionnelles comptent (rapidité, sécurité, fiabilité, robustesse...).

Le langage C est un langage compilé. Ainsi un programme C est décrit par un ensemble de fichiers textes, portant des extensions .C et .H, et nommés sources. La compilation se réalise en 4 phases successives :

  • Le traitement par le pré-processeur : les fichiers sources sont analysés par le pré-processeur, qui effectue des transformations purement textuelles selon des directives (remplacement de chaines de caractères, inclusion de fichiers, compilation conditionnelle...).
  • La compilation : la compilation proprement dite, traduit le fichier généré par le pré-processeur en code assembleur, c’est-à-dire une suite d’instructions formées de mnémoniques propre à l’architecture du processeur concerné.
  • L’assemblage : cette opération transforme le code assembleur en un binaire, c’est-à-dire en instructions directement compréhensibles par le processeur.
  • L’édition de liens : un programme est généralement séparé en plusieurs fichiers sources. Une fois chaque fichier source assemblé, il faut les lier entre eux pour former l’exécutable final (le fichier qui servira à lancer le programme).


V- Compilation d'un programme

Il existe un grand nombre de compilateurs C pour chaque systèmes d’exploitations (Windows, Linux, Mac). Dans le cadre de nos exercices, nous utiliserons le compilateur libre Linux GCC, porté sous Windows sous le nom de minGW.

Nous vous présentons ici les commandes de bases pour transformer un fichier source en programme executable. Elle s’effectue généralement en deux étapes :

  • Transformation du code source en fichier binaire (.o)

Code : Tout sélectionner
  1.  gcc -O3 -Wall -c prog.c


  • Regroupement des différents fichiers binaires constituant le programme (édition de liens)
Code : Tout sélectionner
  1.  gcc -o prog prog.o


Lorsque tous les fichiers sources sont présents dans un même répertoire, l’étape de compilation peut-être unique et simplifiée :
Code : Tout sélectionner
  1.  gcc prog.c



VI- Détails des options

  • -O: effectue des optimisations sur le code généré. La compilation peut alors prendre plus de temps et utiliser plus de mémoire.
  • -Wall: active des messages d’avertissement supplémentaires.
  • -c: demande au compilateur de n’effectuer que la première étape de compilation .
  • -o: permet de préciser un nom de fichier à l’exécutable final.

VII- Les bases du langage

A- Les mots clés

Le C est un langage défini par un certain nombre de mots clés et de symboles réservés. Vous ne pourrez pas utiliser ces identifiants en tant qu’identifiant de variable ou de fonction. En voici la liste, par ordre alphabétique :

Code : Tout sélectionner
  1. auto
  2. break
  3. case
  4. char
  5. const
  6. continue
  7. default
  8. do
  9. double
  10. else
  11. enum
  12. extern
  13. float
  14. for
  15. goto
  16. if
  17. int
  18. long
  19. register
  20. return
  21. short
  22. signed
  23. sizeof
  24. static
  25. struct
  26. switch
  27. typedef
  28. union
  29. unsigned
  30. void
  31. volatile
  32. while



B- Les commentaires

Les commentaires sont indispensables à la compréhension de n’importe quel programme informatique non triviale. Ils permettent le travail collaboratif et la maintenance.

Le langage C propose deux types de commentaires :

  • Les commentaires mono-lignes (introduit dans la norme C99) :
Code : Tout sélectionner
  1.  // Ceci est un commentaire mono-ligne


  • Les commentaires multi-lignes :
Code : Tout sélectionner
  1.  /* Ceci est un
  2.    commentaire
  3.    multi-lignes
  4. */


Il existe plusieurs normes de formalisation de commentaires, nous vous recommandons de vous reporter à l’outil doxygen, qui est un générateur de documentation automatique référent.


C- Structure générale d’un programme C

D’une manière générale, un programme consiste en un ensemble organisé de sous programmes appelés fonctions organisés entre eux. La fonction principale d’un programme appelée main,constitue le point d’entrée (et de sortie) d’un programme.
Voici à quoi ressemble un programme C minimaliste qui affichera sur la console le fameux : « Hello World »

Code : Tout sélectionner
  1. #include <stdio.h> // Directive de preprocesseur
  2. int main(int argc, char** argv) {
  3.   printf("Hello world!");
  4. }


Un programme est donc constitué d’un ensemble de fonctions, mais aussi de variables qui représentes des données ainsi que des structures de contrôles qui organisent le déroulement du programme (du flot d’exécution).

D- Notion d’identification

Un identificateur permet de donner un nom à une entité d’un programme. Qu’il s’agisse d’une fonction ou d’une variable, ils sont sujets aux règles suivantes :

  • Ils sont formés d’une suite de lettres (’a’ à ’z’ et ’A’ à ’Z’), de chiffres (0 à 9) et du signe ’_’. En particulier, les lettres accentuées sont interdites.
  • Le premier caractère de cette suite ne peut pas être un chiffre.
  • Les identificateurs sont sensibles à la casse : abc et Abc sont 2 identificateurs distincts.

Etant donné que l’identification d’une entité est laissée libre au développeur, il est fortement conseillé d’utiliser des noms significatifs !

Code : Tout sélectionner
  1. int _is_connected = 0; // Valide.
  2. int 2_good_4_me = 12; // Invalide.
  3. char* message = 12; // Valide.



E- Notion de variable

Une variable est un espace mémoire situé en mémoire et pouvant stocker, selon son type, des données.
Une variable est définie(déclarée) par un un identifiant, précédée d’un type et éventuellement succédée d’un opérateur d’affectation et d’une valeur pour en effectuer son initialisation.

Code : Tout sélectionner
  1.  int _is_connected = 0;


Dans l’exemple ci-dessus, on déclare une variable identifiée sous le nom de "_is_connected" de type int (entière) et initialisée à la valeur 0.
Cette variable sera donc accessible, dans la limite de sa portée, sous cet identifiant.

Code : Tout sélectionner
  1. int _is_connected = 0; // Valide.
  2.     _is_connected = 1;
  3. int connection;
  4.     connection = is_connected;


Dans l’exemple ci-dessus, la variable est accédée à la ligne 2 en mode écriture, et à la ligne 4 en mode lecture.
Remarque : Un identifiant est unique à l’intérieur de sa portée.


F- Les types primitifs

Il s’agit des types de bases définis en standard par le langage. Ils permettent de définir la nature d’une variable. Le langage C est très faiblements typé, il ne propose que des types numériques.


G- Les entiers

Les types entiers sont les plus utilisés et représentes des valeurs entières. Le langage C permet de préciser leur taille en octet et donc l’espace de valeur qu’ils peuvent prendre.

Code : Tout sélectionner
  1. short int mask;
  2. int i;
  3. long int id;
  4. unsigned int count;


Le mot clé unsigned indique l’espace de valeur prit par count et sur l’ensemble des entiers naturels(>=0). Par défaut les entiers sont signés.

Le type int est calé sur la longueur du mot machine, en d’autres termes, si le processeur est un 16 bits, ce sera sur 2 octets, un 32 bits sur 4 octets. Les autres types sont fixes. Le mot machine étant le plus rapide à traiter (puisqu’il ne nécessite pas de conversion).

Tableau récapitulatif des types :

TypeTaille mémoireIntervalle
char1 octet[-128 ;127]
unsigned char1 octet[0; 255]
int2,4,8 octets[-2¹⁵; 2¹⁵-1] ou [-2³¹; 2³¹-1] ...
unsigned int2,4,8 octets[0; 2¹⁶-1] ou [0; 2³²-1] ...
short int2 octets[-2¹⁵; 2¹⁵-1]
unsigned short int2 octets[0; 2¹⁶-1]
long4 octets[-2³¹; 2³¹-1]
unsigned long4 octets[0; 2³²-1]
long long *8 octets[-2⁶³; 2⁶³-1]
unsigned long long *8 octets[0; 2⁶⁴-1]


* Dépend du compilateur utilisé.

Les valeurs limites des différents types sont définies dans le fichier header <limits.h>


H- Représentation des valeurs

Le langage C permet de représenter les valeurs entières selon 3 bases :

Base 10, Décimale
c’est la base par défaut.

Code : Tout sélectionner
  1.               short int mask = 372;


Base 8, Octale
On commence par un 0 suivi de chiffres octaux

Code : Tout sélectionner
  1.               short int mask = 0477;


Base 16, Hexadécimale
On commence par un 0x ou 0X suivi de chiffres héxadécimaux

Code : Tout sélectionner
  1.               short int mask = 0x5A2b;



I- Les caractères

Le C propose un type de variable pour représenté la notion de caractère, c’est-à-dire une donnée devant être affichée, typiquement une lettre, un chiffre, un espace, un retour à la ligne...
Il s’agit en fait d’un entier codé sur 8 bits interprété comme un caractère utilisé sur la machine (il s’agit en général du code ASCII de ce caractère).

Code : Tout sélectionner
  1.  /* Declaration d’une variable c1 de type char a laquelle on affecte la valeur ’a’.
  2. Important : Noter l’utilisation du simple quote
  3. */
  4. char c1 = 'a';
  5. char c2 = 97; //c2 correspond egalement au caractere ’a’, puisque dans la table ASCII, la lettre 'a' représente la valeur 97.


Table des principaux code ASCII Caractères particuliers

Il existe un certain nombre de caractères particuliers utilisant le caractère d’échappement \ dont les principaux sont les suivants

Caractère'\n''\t''\b''\'''\"'
Sémantiqueretour à la lignetabulationbackspace'"



J- Les flottants

On distingue 3 types de flottants. La différence entre eux est leur précision. Du plus faible à la plus forte, on a float, double, long double.

Code : Tout sélectionner
  1.  double Pi = 3.14159;


TypeTaille mémoireIntervallePrécision
float4 octets[1,2∗10⁻³⁸; 3,4∗10³⁸]6 chiffres décimaux
double8 octets[2,3∗10⁻³⁰⁸; 1,7∗10^³⁰⁸]15 chiffres décimaux
long double10 octets[3,4∗10⁻⁴⁹³²; 1,1∗10⁴⁹³²]19 chiffres décimaux



K- Le type void

On a vu que toute variable C était typée, de même que toute valeur de retour d’une fonction. Mais il peut arriver qu’aucune valeur ne soit disponible.

Pour exprimer l’idée de ”aucune valeur”, on utilise le mot-clé void. Ce type est utilisé dans trois situations :
Les expressions de type void : on les rencontre principalement dans la déclaration de fonctions qui n’ont pas de valeur de retour.

Code : Tout sélectionner
  1. void exit (int status);


Le prototype de fonctions sans paramètres

Code : Tout sélectionner
  1. int rand(void);


A noter qu’en pratique, on écrira plus simplement :

Code : Tout sélectionner
  1. int rand();


Les pointeurs vers le type void : le type void * est le type pointeur générique, c’est à dire qu’il est capable de pointer vers n’importe quel type d’objet. Il représente donc l’adresse de l’objet et non son type.


VIII- La syntaxe du langage

A- Notion d’expression

Code : Tout sélectionner
  1. 4 * 512 // Type: int
  2. 4 + 6 * 512 // Type: int; equivalent to 4 + (6 * 512)
  3. 1.0 + sin(x) // Type: double
  4. srand((unsigned)time(NULL)) // Appel de fonction; type: void
  5. (int*)malloc(count*sizeof(int)) // Appel de fonction; type: int *


Une expression est une combination d’opérateurs et d’opérandes.
Dans les cas les plus simples, une expression se résume à une constante, une variable ou un appel de fonction.
Des expressions peuvent également être utilisées comme opérandes et être jointes ensembles par des opérateurs, pour obtenir des expressions plus complexes.
Toute expression a un type et si ce type n’est pas void, c'est une valeur.


B- Opérateurs arithmétiques

Les principaux opérateurs arithmétiques sont résumés dans le tableau. Les opérandes de ces opérateurs peuvent appartenir a tout type arithmétique, à l’exception du % qui requière des opérandes de type entier.
On peut effectuer une conversion de type aux opérandes. Le résultat de l’opération prend le type de cette conversion. Ainsi ; 2.0/3 est équivalent à 2.0/3.0 et le résultat est de type float.
Le résultat d’une division d’entiers est aussi un entier !

Code : Tout sélectionner
  1. 6 / 4         // Resultat: 1
  2. 6 % 4        // Resultat: 2
  3. 6.0 / 4.0  // Resultat: 1.5
  4. 6.0 / 4     // Resultat: 1.5


OpérateurTraductionExempleRésultat
+Additionx + yl'addition de x et y
-Soustractionx - yla soustraction de x et y
*Multiplicationx * yla multiplication de x et y
/Divisionx / yla division de x et y
%Restex % yReste de la division euclidienne de x par y
+(unaire)signe positif+xvaleur de x
-(unaire)signe négatif-xnégation arithmétique de x
++(unaire)Incrémentx++ ou ++xx = x+1, ++x : préincrément; incrément, puis évaluation. x++ : postincrément; évaluation puis incrément.
--(unaire)Décrémentx-- ou --xx = x-1, --x : prédécrément; décrément, puis évaluation. x-- : postdécrément; évaluation puis décrément.


Code : Tout sélectionner
  1. int x = 0;
  2. int y = x++; // y vaut 0;
  3. int z = x;   // z vaut 1;
  4. int b = ++x; // b vaut 2;



C- Opérateurs d’affectation

Les opérateurs d’affectation permettent d’écrire dans une variable. On en distingue 2 types

OpérateurTraductionExempleRésultat
=Affectation simplex = yplace la value de y dans x
(op)=Affectation composéex += yplace la valeur de x + y dans x (x=x+y)


Exemple d’opérateurs composés : += -= *= /= %= &= ^= |= <<= >>=


D- Opérateurs relationnels

Toute comparaison est une expression de type int qui renvoie la valeur 0 (false) ou 1 (true). Il faut que les opérandes soient du même type arithmétique (ou des pointeurs sur des objets de même type).

OpérateurTraductionExemple
<strictement inférieurx < y
<=inférieur ou égalx <= y
>strictement supérieurx > y
>=supérieur ou égalx >= y
==égalitéx == y
!=inégalitéx != y


Attention : Une erreur classique est de confondre l’opérateur d’égalité (==) avec celui d’affectation (=)

Code : Tout sélectionner
  1. int i = 2;
  2. if (x = 4) printf("valeur de x : %d", x);
  3. if (x == 4) printf("valeur de x : %d", x);


Dans l’exemple ci-dessus, le code est correcte, mais le résultat n’est sans doute pas celui qu’on attend : les deux conditions sont évaluées à vrai !

Dans la première condition : on affecte 4 dans x, puis on évalue x (qui est différent de 0 donc vrai) et on affiche.
Dans la seconde condition, on compare x qui vaut désormais 4 à 4 donc vrai, et on affiche.

Pour éviter ce genre d’étourderie qui peut coûter des heures en debuggage, une bonne bratique simple consiste à mettre systématique les valeurs littéraires (ou en lecture seule à gauche)

Code : Tout sélectionner
  1. int i = 2;
  2. if (4 = x) printf("valeur de x : %d", x);
  3. if (4 == x) printf("valeur de x : %d", x);


Ainsi la première condition provoquera une erreur de compilation, et vous pourrez corriger immédiatement l’erreur.


E- Opérateurs logiques

Les opérateurs logiques permettent de combiner le résultat de plusieurs expressions de comparaison en une seule expression logique.
Les opérandes des opérateurs logiques peuvent être n’importe quel scalaire (i.e arithmétique ou pointeur).
Toute valeur différente de 0 est interprétée comme vraie (et 0 correspond `a ’faux’).
Comme pour les expressions relationnelles, les expressions logiques renvoient une valeur entière (0=false ; 1=true).

Remarque : les opérateurs && et || évaluent les opérandes de gauche à droite et le résultat est connu dès l’opérande de gauche. Ainsi, l’opérande de droite n’est évaluée que si celle de gauche est vraie dans le cas de l'opérateur && ou fausse dans le cas de l'opérateur ||

Code : Tout sélectionner
  1. if (0 && mask) printf("Jamais de la vie"); // mask n'est jamais évalué.
  2. if (1 || mask) printf("Jamais de la vie"); // mask n'est jamais évalué.


OpérateurTraductionExemple
&&ET Logiquex && y
||OU Logiquex ||= y
!NON Logique!x



F- Opérateurs bit à bit

Les opérateurs bits à bits n’op��rent que sur des entiers. Les opérandes sont interprétées bits par bits (le bit 1 correspondant à une valeur vraie, 0 est considérée comme une valeur fausse).

OpérateurTraductionExempleRésultat
&ET bit à bitx & y1 si les bits de x et y valent 1
|OU bit à bitx | y1 si le bit de x et/ou de y vaut 1
^XOR bit à bitx ^ y1 si le bit de x ou de y vaut 1
~NON bit à bitx ~ y1 si le bit de x est 0
<<décalage à gauchex << ydécale chaque bit de x de y positions vers la gauche
>>décalage à droitex >> ydécale chaque bit de x de y positions vers la droite


Voici quelques exemples représentatifs :

xyOpérationRésultat
141110 91001 x & y 81000
141110 91001 x | y 151111
141110 91001 x ^ y 70111
141110~x10001
141110 20010 x << y56111000
141110 20010 x >> y311



IX- Les structures décisionnelles

Les structures décisionnelles sont des structures de controlles du flot d’exécuté qui permet d’orienté le déroulement du programme en fonction de l’évaluation du expression booléenne.

A- Instruction if

Cette première instruction de la famille des if permet d’exécuter une instruction ou un bloc d’instruction si une condition est remplie

Syntaxe

if ( expression )
Instruction ou Bloc d'instruction

Exemple :

Code : Tout sélectionner
  1. int a = 5;
  2. int b = 10;
  3. if (! b % a )
  4.    printf("b est un multiple de a");


Instruction if avec alternative simple

Cette seconde instruction de la famille des if permet d’exécuter une instruction ou un bloc d’instruction si une condition est remplie ou une autre instruction ou bloc d’instruction sinon.

Syntaxe

if ( expression )
Instruction ou Bloc d'instruction
else
Instruction2 ou Bloc d'instruction2

Exemple

Code : Tout sélectionner
  1.  
  2. int a = 5;
  3. int b = 10;
  4. if ( a>b )
  5.   printf("a est strictement supérieur à b);
  6. else
  7.  printf("b est supérieur ou égal à a);
  8.  


Instruction if avec alternative multiple

Cette dernière instruction de la famille des if permet de proposer des alternatives multiples par des couplages des instructions précédentes.

Syntaxe

if ( expression )
Instruction ou Bloc d'instruction
else if ( expression2)
Instruction2 ou Bloc d'instruction2
else ...

Exemple

Code : Tout sélectionner
  1. int a = 5;
  2. int b = 10;
  3. if ( a>b )
  4.   printf("a est strictement supérieur à b);
  5. else if (a<b)
  6.  printf("b est strictement supérieur à a);
  7. else
  8.   printf("a est égal à b);


B- Instruction Switch

L’instruction d’aiguillage switch permet de tester une variable de type entière parmis un ensemble de constantes de type entière. La définition syntaxique est la suivante:

Syntaxe

Code : Tout sélectionner
  1. switch ( valeur_entiere ) {
  2.   case '2' : instruction1;
  3.   case 2   : instruction2; instruction3;
  4.   case '5' : instruction4;break;
  5.   case  7 : instruction5;
  6.   default : instruction6;  
  7. }


Cette structure est à utiliser avec précaution, car elle n’est pas débranchante. En effet, lorsque la valeur entière est égal à l’un des cas, toutes les instructions qui suivent sont executés jusqu’à rencontrer l’instruction break. Cet type de comportement induit de nombreuses erreurs aux développeurs débutants. C’est pourquoi nous déconseillons fortement l’utilisation de switch lorsqu’ils sont utilisés en substitue de structure if.

Dans l’exemple précédent si la valeur_entiere vaut 2, les instructions 2,3,4 seront executés.
Dans l’exemple précédent si la valeur_entiere vaut 5, l’instruction 6 sera executé.
Dans l’exemple précédent si la valeur_entiere vaut 7, les instructions 5 et 6 seront executés.
L’instruction default est exécuté si aucun cas n’a été levé ont si aucun break n’est présent entre le case levé et l’instruction default.

C- L’opérateur Ternaire

L’opérateur ternaire est une forme condensée de l’instruction if/else qui renvoi une valeur.

Syntaxe

valeur = (expression)? valeur_si_vrai : valeur_si_faux;

Exemple

Code : Tout sélectionner
  1. int a = 5;
  2. int b = 10;
  3. int max;
  4. // Avec la structure if
  5. if (a>b)
  6.  max = a;
  7. else
  8.  max = b;
  9. // forme condensée
  10. max = (a>b)?a:b;


Dans de nombreux cas, l’utilisation de cet opérateur permet d’alléger la lecture du code et surtout d’éviter de déclarer inutilement des variables.

Cas d’application Exemple

Code : Tout sélectionner
  1. int max1(int a, int b) {
  2.   int max;
  3.   if (a>b)
  4.     max = a;
  5.   else
  6.     max = b;
  7.   return max;
  8. }
  9.  
  10. int max(int a, int b) {
  11.   return (a>b)?a:b;
  12. }



DJ Kin-C
 DJ Kin-C
Avatar de l’utilisateur

Stormtrooper
 
 
Messages : 38
Âge : 26
Inscription : Lun 18 Avr 2011 12:27
Dernière visite : Lun 12 Aoû 2013 16:30
Pays : France

Publicités

Messagepar darky » Lun 7 Mai 2012 16:07

Image
Tutoriel validé !
Votre tutoriel a été validé par
darky.
 darky
Avatar de l’utilisateur

Administrateur
 
 
Messages : 2453
Âge : 24
Inscription : Dim 3 Avr 2011 17:44
Dernière visite : Lun 10 Fév 2014 09:58
Localisation : Côté Obscur
Pays : France
OS : Windows 8
Navigateur : Chrome


Retourner vers Tutoriels sur le C et le C++

Qui est en ligne

Utilisateurs parcourant ce forum: Aucun utilisateur enregistré et 1 invité