Social Icons

langage de programmation

 

Presentation

Le langage C a ete concu pour l'ecriture de systemes, en particulier le systeme unix. Pour cette raison, ses concepteurs ont fait une separation nette entre ce qui est purement algorithmique (declarations, instructions, etc.) et tout ce qui est interaction avec le systeme (entrees sorties, allocation de memoire, etc.) qui est realise par appel de fonctions se trouvant dans une bibliotheque dite bibliotheque standard. Cette coupure se retrouve dans la norme qui est composee essentiellement de deux grands chapitres, les chapitres (( langage )) et (( bibliotheque )).
Ce manuel se donne comme objectif de donner une vue d'ensemble du langage, mais pas de la bibliotheque standard. De la bibliotheque standard ne seront presentees de maniere complete que les fonctions permettant de realiser les entrees-sorties et la gestion memoire. Cependant, la liste exhaustive des noms des fonctions de la bibliotheque, classes par type d'utilisation, est donnee dans le chapitre 10.

Les phases de compilation

Les compilateurs C font subir deux transformations aux programmes :
1. un preprocesseur realise des transformations d'ordre purement textuel, pour rendre des services du type inclusion de source, compilation conditionnelle, et traitement de macros ;
2. le compilateur proprement dit prend le texte genere par le preprocesseur et le traduit en instructions machine.
La fonction de preprocesseur est assez souvent implementee par un programme separe (cpp sous unix) qui est automatiquement appele par le compilateur.

Les mots-clés

  Le langage C est un langage à mots-clés, ce qui signifie qu'un certain nombre de mots sont réservés pour le langage lui-même et ne peuvent donc pas être utilisés comme identificateurs. La liste exhaustive des mots-clés est la suivante :
        auto            double          int             struct
        break           else            long            switch
        case            enum            register        typedef
        char            extern          return          union
        const           float           short           unsigned
        continue        for             signed          void
        default         goto            sizeof          volatile
        do              if              static          while

Attention

Si le compilateur produit un message d'erreur syntaxique incompréhensible il est recommandé d'avoir le réflexe de consulter la liste des mots clés pour vérifier que l'on a pas pris comme identificateur un mot-clé. Si le lecteur désire être convaincu, il lui est suggéré de donner le nom long à une variable entière.

Les commentaires

 
Syntaxe :
Les commentaires débutent par /* et se terminent par */. Exemple :
/*   Ceci est un commentaire   */
Toute occurrence de /* est interprétée comme le début d'un commentaire sauf dans une chaîne littérale, ou un commentaire (les commentaires ne peuvent donc pas être imbriqués).
 
Recommandations :
Dans le domaine général de la programmation, (pas seulement le langage C), il est admis qu'il faille commenter selon les niveaux suivants :
-
unité de compilation : pour indiquer le nom de l'auteur, les droits de copyright, la date de création, les dates et auteurs des différentes modifications, ainsi que la raison d'être de l'unité ;
-
procédure : pour indiquer les paramètres et la raison d'être de la procédure ;
-
groupe d'intructions : pour exprimer ce que réalise une fraction significative d'une procédure ;
-
déclaration ou instruction : le plus bas niveau de commentaire.
 L'erreur classique avec les commentaires est d'oublier la séquence fermante */. Dans ce cas, le compilateur va considérer que le commentaire se poursuit jusqu'à la fin du prochain commentaire et ceci peut ne pas générer d'erreur syntaxique.
Exemple :
instruction
/* premier commentaire
instruction
...
instruction
/* second commentaire */
instruction
On voit que dans ce cas, tout un ensemble d'instructions sera ignoré par le compilateur sans générer le moindre message d'erreur

Les types de base

Les caractères

Le mot-clé désignant les caractères est char. Un objet de ce type doit pouvoir contenir le code de n'importe quel caractère de l'ensemble des caractères utilisé sur la machine. Le codage des caractères n'est pas défini par le langage : c'est un choix d'implémentation. Cependant, dans la grande majorité des cas, le code utilisé est le code dit ASCII, ou un surensemble comme par exemple la norme ISO-8859

 

Les entiers

          Le mot clé désignant les entiers est int. Les entiers peuvent être affectés de deux types d'attributs : un attribut de précision et un attribut de représentation.

On peut combiner attribut de précision et attribut de représentation et avoir par exemple un unsigned long int. En résumé, on dispose donc de six types d'entiers : int, short int, long int (tous trois signés) et unsigned int, unsigned short int et unsigned long int.

Les flottants

    Il existe trois types de flottants correspondants à trois précisions possibles. En allant de la précision la plus faible vers la plus forte, on dispose des types float, double et long double. La précision effectivement utilisée pour chacun de ces types dépend de l'implémentation.

Les types prédéfinis

Le C est un langage typé. Cela signifie en particulier que toute variable, constante ou fonction est d'un type précis. Le type d'un objet définit la façon dont il est représenté en mémoire.

La mémoire de l'ordinateur se décompose en une suite continue d'octets. Chaque octet de la mémoire est caractérisé par son adresse, qui est un entier. Deux octets contigus en mémoire ont des adresses qui diffèrent d'une unité. Quand une variable est définie, il lui est attribué une adresse. Cette variable correspondra à une zone mémoire dont la longueur (le nombre d'octets) est fixée par le type.

La taille mémoire correspondant aux différents types dépend des compilateurs ; toutefois, la norme ANSI spécifie un certain nombre de contraintes.

Les types de base en C concernent les caractères, les entiers et les flottants (nombres réels). Ils sont désignés par les mots-clefs suivants :

char  
int  
float double
short long unsigned


1.5.1  Le type caractère

Le mot-clef chardésigne un objet de type caractère. Un char peut contenir n'importe quel élément du jeu de caractères de la machine utilisée. La plupart du temps, un objet de type char est codé sur un octet ; c'est l'objet le plus élémentaire en C. Le jeu de caractères utilisé correspond généralement au codage ASCII (sur 7 bits). La plupart des machines utilisent désormais le jeu de caractères ISO-8859 (sur 8 bits), dont les 128 premiers caractères correspondent aux caractères ASCII. Les 128 derniers caractères (codés sur 8 bits) sont utilisés pour les caractères propres aux différentes langues. La version ISO-8859-1 (aussi appelée ISO-LATIN-1) est utilisée pour les langues d'Europe occidentale. Ainsi, le caractère de code 232 est le è, le caractère 233 correspond au é...Pour plus de détails sur l'historique du codage des caractères pour les différentes langues ainsi que sur la norme UNICODE (sur 16 bits, qui permet de coder les caractères pour toutes les langues) et sur la norme ISO/IEC-10646 (sur 32 bits, ce qui permet d'ajouter les caractères anciens), consulter l'article de J. André et M. Goossens [1].




  déc. oct. hex.   déc. oct. hex.   déc. oct. hex.
  32 40 20 @ 64 100 40 ` 96 140 60
! 33 41 21 A 65 101 41 a 97 141 61
" 34 42 22 B 66 102 42 b 98 142 62
# 35 43 23 C 67 103 43 c 99 143 63
$ 36 44 24 D 68 104 44 d 100 144 64
% 37 45 25 E 69 105 45 e 101 145 65
& 38 46 26 F 70 106 46 f 102 146 66
' 39 47 27 G 71 107 47 g 103 147 67
( 40 50 28 H 72 110 48 h 104 150 68
) 41 51 29 I 73 111 49 i 105 151 69
* 42 52 2a J 74 112 4a j 106 152 6a
+ 43 53 2b K 75 113 4b k 107 153 6b
, 44 54 2c L 76 114 4c l 108 154 6c
- 45 55 2d M 77 115 4d m 109 155 6d
. 46 56 2e N 78 116 4e n 110 156 6e
/ 47 57 2f O 79 117 4f o 111 157 6f
0 48 60 30 P 80 120 50 p 112 160 70
1 49 61 31 Q 81 121 51 q 113 161 71
2 50 62 32 R 82 122 52 r 114 162 72
3 51 63 33 S 83 123 53 s 115 163 73
4 52 64 34 T 84 124 54 t 116 164 74
5 53 65 35 U 85 125 55 u 117 165 75
6 54 66 36 V 86 126 56 v 118 166 76
7 55 67 37 W 87 127 57 w 119 167 77
8 56 70 38 X 88 130 58 x 120 170 78
9 57 71 39 Y 89 131 59 y 121 171 79
: 58 72 3a Z 90 132 5a z 122 172 7a
; 59 73 3b [ 91 133 5b { 123 173 7b
< 60 74 3c \ 92 134 5c | 124 174 7c
= 61 75 3d ] 93 135 5d } 125 175 7d
> 62 76 3e ^ 94 136 5e ~ 126 176 7e
? 63 77 3f _ 95 137 5f DEL 127 177 7f

Table 1.1: Codes ASCII des caractères imprimables

Une des particularités du type char en C est qu'il peut être assimilé à un entier : tout objet de type char peut être utilisé dans une expression qui utilise des objets de type entier. Par exemple, si c est de type char, l'expression c + 1 est valide. Elle désigne le caractère suivant dans le code ASCII. La table précédente donne le code ASCII (en décimal, en octal et en hexadécimal) des caractères imprimables. Ainsi, le programme suivant imprime le caractère 'B'.

main()
{
  char c = 'A';
  printf("%c", c + 1);
}
Suivant les implémentations, le type char est signé ou non. En cas de doute, il vaut mieux préciser unsigned char ou signed char. Notons que tous les caractères imprimables sont positifs.



1.5.2  Les types entiers

Le mot-clef désignant le type entier est int. Un objet de type int est représenté par un mot ``naturel'' de la machine utilisée, 32 bits pour un DEC alpha ou un PC Intel.

Le type int peut être précédé d'un attribut de précision (short ou long) et/ou d'un attribut de représentation (unsigned).Un objet de type short int a au moins la taille d'un char et au plus la taille d'un int. En général, un short int est codé sur 16 bits. Un objet de type long int a au moins la taille d'un int (64 bits sur un DEC alpha, 32 bits sur un PC Intel).


  DEC Alpha PC Intel (Linux)  
char 8 bits 8 bits caractère
short 16 bits 16 bits entier court
int 32 bits 32 bits entier
long 64 bits 32 bits entier long
long long n.i. 64 bits entier long (non ANSI)

Table 1.2: Les types entiers

Le bit de poids fort d'un entier est son signe. Un entier positif est donc représenté en mémoire par la suite de 32 bits dont le bit de poids fort vaut 0 et les 31 autres bits correspondent à la décomposition de l'entier en base 2. Par exemple, pour des objets de type char (8 bits), l'entier positif 12 sera représenté en mémoire par 00001100. Un entier négatif est, lui, représenté par une suite de 32 bits dont le bit de poids fort vaut 1 et les 31 autres bits correspondent à la valeur absolue de l'entier représentée suivant la technique dite du ``complément à 2''. Cela signifie que l'on exprime la valeur absolue de l'entier sous forme binaire, que l'on prend le complémentaire bit-à-bit de cette valeur et que l'on ajoute 1 au résultat. Ainsi, pour des objets de type signed char (8 bits), -1 sera représenté par 11111111, -2 par 11111110, -12 par par 11110100.Un int peut donc représenter un entier entre -231 et (231-1). L'attribut unsigned spécifie que l'entier n'a pas de signe. Un unsigned int peut donc représenter un entier entre 0 et (232-1). Sur un DEC alpha, on utilisera donc un des types suivants en fonction de la taille des données à stocker :

signed char [-27;27[
unsigned char [0;28[
short int [-215; 215[
unsigned short int [0;216[
int [-231;231[
unsigned int [0;232[
long int (DEC alpha) [-263;263[
unsigned long int (DEC alpha) [0;264[

Plus généralement, les valeurs maximales et minimales des différents types entiers sont définies dans la librairie standard limits.h.


Le mot-clef sizeof a pour syntaxe
sizeof(expression)
expression est un type ou un objet. Le résultat est un entier égal au nombre d'octets nécessaires pour stocker le type ou l'objet. Par exemple
unsigned short x;

taille = sizeof(unsigned short); 
taille = sizeof(x);
Dans les deux cas, taille vaudra 4.

Pour obtenir des programmes portables, on s'efforcera de ne jamais présumer de la taille d'un objet de type entier. On utilisera toujours une des constantes de limits.h ou le résultat obtenu en appliquant l'opérateur sizeof.



1.5.3  Les types flottants

Les types float, double et long double servent à représenter des nombres en virgule flottante. Ils correspondent aux différentes précisions possibles.


  DEC Alpha PC Intel  
float 32 bits 32 bits flottant
double 64 bits 64 bits flottant double précision
long double 64 bits 128 bits flottant quadruple précision

Table 1.3: Les types flottants

Les flottants sont généralement stockés en mémoire sous la représentation de la virgule flottante normalisée. On écrit le nombre sous la forme ``signe  0,mantisse   Bexposant''. En général, B=2. Le digit de poids fort de la mantisse n'est jamais nul.

Un flottant est donc représenté par une suite de bits dont le bit de poids fort correspond au signe du nombre. Le champ du milieu correspond à la représentation binaire de l'exposant alors que les bits de poids faible servent à représenter la mantisse.



1.6  Les constantes

Une constante est une valeur qui apparaît littéralement dans le code source d'un programme, le type de la constante étant déterminé par la façon dont la constante est écrite. Les constantes peuvent être de 4 types : entier, flottant (nombre réel), caractère, énumération. Ces constantes vont être utilisées, par exemple, pour initialiser une variable.



1.6.1  Les constantes entières

Une constante entière peut être représentée de 3 manières différentes suivant la base dans laquelle elle est écrite :
  • décimale : par exemple, 0 et 2437348 sont des constantes entières décimales.
  • octale : la représentation octale d'un entier correspond à sa décomposition en base 8. Les constantes octales doivent commencer par un zéro. Par exemple, les représentations octales des entiers 0 et 255 sont respectivement 00 et 0377.
  • hexadécimale : la représentation hexadécimale d'un entier correspond à sa décomposition en base 16. Les lettres de a à f sont utilisées pour représenter les nombres de 10 à 15. Les constantes hexadécimales doivent commencer par 0x ou 0X. Par exemple, les représentations hexadécimales de 14 et 255 sont respectivement 0xe et 0xff.
Par défaut, une constante décimale est représentée avec le format interne le plus court permettant de la représenter parmi les formats des types int, long int et unsigned long int tandis qu'une constante octale ou hexadécimale est représentée avec le format interne le plus court permettant encore de la représenter parmi les formats des types int, unsigned int, long int et unsigned long int.

On peut cependant spécifier explicitement le format d'une constante entière en la suffixant par u ou U pour indiquer qu'elle est non signée, ou en la suffixant par l ou L pour indiquer qu'elle est de type long. Par exemple :
constante type

1234 int
02322 int /* octal */
0x4D2 int /* hexadécimal */
123456789L long
1234U unsigned int
123456789UL      unsigned long int

1.6.2  Les constantes réelles

Les constantes réelles sont représentées par la notation classique par mantisse et exposant. L'exposant est introduit par la lettre e ou E ; il s'agit d'un nombre décimal éventuellement signé.

Par défaut, une constante réelle est représentée avec le format du type double. On peut cependant influer sur la représentation interne de la constante en lui ajoutant un des suffixes f (indifféremment F) ou l (indifféremment L). Les suffixes f et F forcent la représentation de la constante sous forme d'un float, les suffixes l et L forcent la représentation sous forme d'un long double. Par exemple :
constante type

12.34 double
12.3e-4 double
12.34F float
12.34L long double

1.6.3  Les constantes caractères

Pour désigner un caractère imprimable, il suffit de le mettre entre apostrophes (par ex. 'A' ou '$'). Les seuls caractères imprimables qu'on ne peut pas représenter de cette façon sont l'antislash et l'apostrophe, qui sont respectivement désignés par \\ et \'. Le point d'interrogation et les guillemets peuvent aussi être désignés par les notations \? et \". Les caractères non imprimables peuvent être désignés par '\code-octal'code-octal est le code en octal du caractère. On peut aussi écrire '\xcode-hexa'code-hexa est le code en hexadécimal du caractère (cf. page X). Par exemple, '\33' et '\x1b' désignent le caractère escape. Toutefois, les caractères non-imprimables les plus fréquents disposent aussi d'une notation plus simple :
\n nouvelle ligne \r retour chariot
\t tabulation horizontale \f saut de page
\v tabulation verticale \a signal d'alerte
\b retour arrière

1.6.4  Les constantes chaînes de caractères

Une chaîne de caractères est une suite de caractères entourés par des guillemets. Par exemple,
"Ceci est une chaîne de caractères"
Une chaîne de caractères peut contenir des caractères non imprimables, désignés par les représentations vues précédemment. Par exemple,
"ligne 1 \n ligne 2"
A l'intérieur d'une chaîne de caractères, le caractère " doit être désigné par \". Enfin, le caractère \ suivi d'un passage à la ligne est ignoré. Cela permet de faire tenir de longues chaînes de caractères sur plusieurs lignes. Par exemple,
"ceci est une longue longue  longue longue longue longue longue longue \
chaîne de caractères"

1.7  Les opérateurs

1.7.1  L'affectation

En C, l'affectation est un opérateur à part entière. Elle est symbolisée par le signe =. Sa syntaxe est la suivante :
variable = expression
Le terme de gauche de l'affectation peut être une variable simple, un élément de tableau mais pas une constante. Cette expression a pour effet d'évaluer expression et d'affecter la valeur obtenue à variable. De plus, cette expression possède une valeur, qui est celle expression. Ainsi, l'expression i = 5 vaut 5.

L'affectation effectue une conversion de type implicite : la valeur de l'expression (terme de droite) est convertie dans le type du terme de gauche.Par exemple, le programme suivant
main()
{
  int i, j = 2;
  float x = 2.5;
  i = j + x;                    
  x = x + i;                    
  printf("\n %f \n",x);
}
imprime pour x la valeur 6.5 (et non 7), car dans l'instruction i = j + x;, l'expression j + x a été convertie en entier.



1.7.2  Les opérateurs arithmétiques

Les opérateurs arithmétiques classiques sont l'opérateur unaire - (changement de signe) ainsi que les opérateurs binaires

+ addition
- soustraction
* multiplication
/ division
% reste de la division (modulo)




Ces opérateurs agissent de la façon attendue sur les entiers comme sur les flottants. Leurs seules spécificités sont les suivantes :
  • Contrairement à d'autres langages, le C ne dispose que de la notation / pour désigner à la fois la division entière et la division entre flottants. Si les deux opérandes sont de type entier, l'opérateur / produira une division entière (quotient de la division). Par contre, il délivrera une valeur flottante dès que l'un des opérandes est un flottant. Par exemple,
    float x;
    x = 3 / 2;
    
    affecte à x la valeur 1. Par contre
    x = 3 / 2.;
    
    affecte à x la valeur 1.5.

  • L'opérateur % ne s'applique qu'à des opérandes de type entier. Si l'un des deux opérandes est négatif, le signe du reste dépend de l'implémentation, mais il est en général le même que celui du dividende.
Notons enfin qu'il n'y a pas en C d'opérateur effectuant l'élévation à la puissance. De façon générale, il faut utiliser la fonction pow(x,y) de la librairie math.h pour calculer xy.

1.7.3  Les opérateurs relationnels

> strictement supérieur
>= supérieur ou égal
< strictement inférieur
<= inférieur ou égal
== égal
!= différent

Leur syntaxe est
expression-1 op expression-2
Les deux expressions sont évaluées puis comparées. La valeur rendue est de type int (il n'y a pas de type booléen en C); elle vaut 1 si la condition est vraie, et 0 sinon.

Attention à ne pas confondre l'opérateur de test d'égalité == avec l'opérateur d'affection =. Ainsi, le programme
main()
{
  int a = 0;
  int b = 1;
  if (a = b)
    printf("\n a et b sont egaux \n");
  else
    printf("\n a et b sont differents \n");
}
imprime à l'écran a et b sont egaux !



1.7.4  Les opérateurs logiques booléens

&& et logique
|| ou logique
! négation logique

Comme pour les opérateurs de comparaison, la valeur retournée par ces opérateurs est un int qui vaut 1 si la condition est vraie et 0 sinon.

Dans une expression de type
expression-1 op-1 expression-2 op-2 ...expression-n
l'évaluation se fait de gauche à droite et s'arrête dès que le résultat final est déterminé. Par exemple dans
int i;
int p[10];

if ((i >= 0) && (i <= 9) && !(p[i] == 0))
...
la dernière clause ne sera pas évaluée si i n'est pas entre 0 et 9.



Abonnez-vous par e-mail

Pour recevoire les nouvelles article