Programmation C/Types de base
Le C est un langage typé statiquement : chaque variable, chaque constante et chaque expression, a un type défini à la compilation. Le langage lui-même fournit des types permettant de manipuler des nombres (entiers, réels ou complexes) ou des caractères (eux-mêmes étant manipulés comme des entiers spéciaux), et permet de construire des types plus complexes à partir de ces premiers, par exemple en groupant des données de même type en tableaux, ou des données de types différents dans des structures. Dans ce chapitre, nous étudierons les types de base fournis par le C, l'étude des types complexes étant faite dans la suite du livre.
Entiers.
Il y a cinq types de variables entières (« integer » en anglais) :
Comme évoqué en introduction, le type caractère codice_1 est particulier, et sera étudié en détail plus bas.
Les types entiers peuvent prendre les modificateurs codice_10 et codice_11 qui permettent respectivement d'obtenir un type signé ou non signé. Ces modificateurs ne changent pas la taille des types. Le langage ne définit pas exactement leur taille, mais définit un domaine de valeurs minimal pour chacun.
Représentation des entiers signés.
La norme C tient compte des anciennes représentations des nombres signés telles que le signe+valeur absolue et le complément à 1. Ces deux représentations sont brièvement expliquées ci-dessous :
Ces deux représentations peuvent représenter la valeur nulle de deux manières différentes.
La représentation moderne des nombres négatifs utilise le complément à 2 (CPL2) qui consiste à représenter les nombres négatifs comme le complément à 1 et en ajoutant 1. Sur un nombre fixe de bits, la valeur 0 n'a qu'une seule représentation : +0 (000...000) et -0 (111...111 + 1 = (1)000...000) ont deux représentations identiques. Sur N bits on peut donc représenter tout nombre entre -(2N-1) "(100...000)" et +(2N-1-1) "(011...111)". Cette représentation possède donc un domaine plus large.
Le tableau ci-dessous donne le domaine des valeurs quelle que soit la représentation utilisée (SVA, CPL1 ou CPL2) :
Cette table signifie qu'un programme peut utiliser sans problème une variable de type codice_4 pour stocker la valeur 215-1, quel que soit le compilateur ou la machine sur laquelle va tourner le programme.
Par contre, une implémentation C peut fournir des domaines de valeurs plus larges que ceux indiqués au-dessus :
Les processeurs modernes supportent un grand nombre de bits, pouvant autoriser les compilateurs à fournir des types stockés sur un plus grand nombre de bits que le nombre minimal indiqué par la norme. Cependant des processeurs plus anciens sont encore utilisés de nos jours (coût réduit) sur des systèmes embarqués.
Il est donc important de vérifier que les valeurs utilisées puissent être stockées dans les variables.
Par exemple, cela permet l'utilisation d'une bibliothèque C (exemple : un décodeur vidéo) sur un système embarqué.
Dans le cas où une bibliothèque assume une taille des types plus grande que supporté par le compilateur pour le processeur, il faudra effectuer des modifications du code source pour que la bibliothèque soit utilisable sur le système embarqué.
Par ailleurs, une relation d'ordre entre ces domaines de valeurs est garantie ; qui peut être exprimée ainsi :
 domaine(char) ≤ domaine(short) ≤ domaine(int) ≤ domaine(long) ≤ domaine(long long)
Cela signifie que toutes les valeurs possibles pour une variable du type codice_1 sont aussi utilisables pour les autres types ; mais aussi que, par exemple, une valeur valide pour le type codice_4 peut ne pas être représentable dans une variable de type codice_3.
Si vous ne savez pas quel type donner à une variable de type entier, le type codice_4 est par défaut le meilleur choix (à condition que votre donnée ne dépasse pas 215-1) : ce type est la plupart du temps représenté au niveau matériel par un « mot machine », c'est-à-dire qu'il est adapté à la taille que la machine peut traiter directement (il fait usuellement 32 bits sur un PC 32 bits, par exemple). Cela permet un traitement plus rapide par le matériel. De plus, beaucoup de bibliothèques (que ce soit celle fournie par le langage C ou d'autres) utilisent ce type pour passer des entiers, ce qui fait que l'utilisation de ces bibliothèques sera plus aisée.
Par ailleurs, un utilisateur peut connaître les domaines de valeurs exacts de sa machine en utilisant l'en-tête codice_19.
Portabilité apportée par C99.
L'incertitude sur l'intervalle de valeur de chaque type en fonction de la machine peut s'avérer extrêmement gênante, pour ne pas dire rédhibitoire. En effet, certains programmes peuvent nécessiter un type de données de taille fixe et cependant être destinés à être portables. Pour ces programmes, les types entiers du C ne sont pas suffisants. "Beaucoup" d'extensions ont été rajoutées pour définir explicitement des types entiers à intervalle fixe (8, 16, 32 bits...) à partir des types de base, avec une nomenclature loin d'être homogène d'un compilateur à l'autre (ce qui, loin de résoudre le problème, ne faisait que le déplacer). 
La norme ISO C99 décide une bonne fois pour toute de définir, dans l'en-tête <stdint.h>, plusieurs nouveaux types où codice_20 représente un nombre entier définissant la taille requise en bit :
Cet en-tête définit aussi des constantes pour les valeurs minimales et maximales de chaque type.
L'include <inttypes.h> définit les constantes symboliques à utiliser pour imprimer ces nouveaux types avec les fonctions de la famille de printf (PRIxxx) et les lire avec celles de scanf (SCNxxx).
Constantes numériques entières.
Il existe différentes suites de caractères qui sont reconnues comme étant des constantes numériques entières :
Par défaut, une constante numérique entière est de type codice_4 et, si sa valeur est trop grande pour le type codice_4, elle prend celle du type « plus grand » suffisant. Comme les domaines de valeurs des types peuvent varier suivant la machine, le type effectif d'une constante peut lui aussi varier. Cela peut s'avérer problématique lors de passage de paramètres à des fonctions à nombre variable d'arguments, par exemple. À cause de cela, il est recommandé de forcer le type de la constante en le postfixant des attributs suivants :
codice_33 peut être combiné à codice_34 et codice_37 pour obtenir les types codice_42 et codice_43, respectivement. Lorsqu'une constante est suffixée, mais que sa valeur est trop grande pour le type demandé, le même processus de recherche de type « assez grand » est utilisé.
Débordement.
Sur une machine donnée, un type entier a un domaine de valeurs fixe. Considérons qu'on travaille sur un PC en 32 bits, en complément à deux : sur un tel ordinateur, le type codice_4 varie souvent de -231 à 231-1. Cela permet de manipuler sans problème des valeurs dans ce domaine. Par contre, si on utilise des valeurs hors du domaine, par exemple 232, et qu'on essaye de la stocker dans une variable de type codice_4 sur une telle machine, que se passe-t-il ?
La réponse dépend du type:
Exemples : On suppose que le type codice_47 est codé sur 8 bits. Alors une valeur de ce type peut aller de 0 à 28-1, soit 255. Par la règle précédente, les conversions se feront donc modulo 255 + 1, soit 256. On considère le programme suivant :
int main(void)
 unsigned char c = 300;
 /* %hhu sert à dire à printf() qu'on veut afficher un unsigned char */
 printf("La variable c vaut %hhu.\n", c);
 c = -5;
 printf("La variable c vaut %hhu.\n", c);
 return 0;
Le résultat du programme est :
 La variable c vaut 44.
 La variable c vaut 251.
En effet, on a 300 - 256 = 44 et -5 + 256 = 251.
De même :
int main(void)
 signed char c = 300;
 /* %hhd sert à dire à printf() qu'on veut afficher un signed char */
 printf("La variable c vaut %hhd.\n", c);
 c = -300;
 printf("La variable c vaut %hhd.\n", c);
 return 0;
Le résultat du programme peut alors être :
 La variable c vaut 44.
 La variable c vaut -44.
Sur une telle machine, les types signés sont traités de la même manière que les types non signés.
Si vous essayez de compiler ces deux programmes, votre compilateur pourra détecter les débordements et vous en avertir (GCC le fait).
Réels.
Les nombres réels ne pouvant tous être représentés, sont approximés par des nombres à virgule flottante. Comme dans le cas des entiers, il existe plusieurs types de nombre à virgule flottante. En voici la liste triée par précision croissante :
La norme C90 était assez floue concernant les nombres à virgule flottante, leurs représentations, la précision des opérations, etc., ce qui fait que c'était un des domaines où la conception de programmes utilisant les nombres flottants était chose peu aisée. Le C99 a clarifié les choses en précisant qu'une implémentation C devait respecter la norme IEC 60559:1989 "Arithmétique binaire en virgule flottante pour systèmes à microprocesseur". Cette norme (dérivée de ) définit des formats de données pour les nombres à virgule flottante, ainsi que des opérations et fonctions sur ces nombres. Elle garantit, entre autres :
Elle définit de plus comment sont gérés les cas exceptionnels, comme les infinis, les "NaN" (pour "Not a Number", résultant par exemple de la division 0/0), etc.
Les types flottants du C correspondent aux type IEC 60559 de la manière suivante :
Constantes réelles.
Une suite de caractères représente une constante à virgule flottante si :
Dans le deuxième cas, le "nombre" peut être soit un entier, soit un réel du premier cas.
Les constantes sont de type codice_51 par défaut. Pour demander le type codice_53, il faut la suffixer par codice_54 ou codice_55, et pour le type codice_56 par codice_57 ou codice_34.
Arithmétique.
Une attention particulière doit être portée sur la précision des types réels. Ces différents types ne font qu'approximer l'ensemble des nombres réels, avec une précision finie. Des erreurs d'arrondis sont à prévoir, ce qui est très problématique pour des domaines qui n'en tolèrent pas (notamment pour les applications financières, il est conseillé de ne pas utiliser de calcul en virgule flottante).
Le type codice_53 en particulier a une précision minimale, qui est bien souvent insuffisante. Voici un exemple classique d'erreur à ne pas faire qui illustre les problèmes liés à la précision des types flottants :
int main(void)
 float i = 0;
 int j;
 for (j = 0; j < 1000; j ++)
 i += 0.1;
 printf("i = %f\n", i);
 return 0;
Le résultat est 99,999046, ce qui montre que la précision du type codice_53 est en général mauvaise, d'autant plus que le nombre 0,1 n'est pas représentable de manière exacte en binaire. Il est ainsi conseillé d'utiliser le type codice_51 à la place de codice_53 autant que possible. Dans ce cas de figure, il est préférable d'éviter les accumulations d'erreurs infinitésimales, en réécrivant le code de la manière suivante :
int main(void)
 float i;
 int j = 1000;
 i = j * 0.1;
 printf("i = %f\n", i);
 return 0;
Le résultat est alors 100.0, sans aucune erreur d'accumulation et d'arrondis.
Pour plus d'informations sur ce domaine, un wikilivre Arithmétique flottante est disponible.
Caractères.
À l'origine, le type permettant de représenter un caractère est codice_1. Même si un codice_1 n'est plus toujours suffisant aujourd'hui pour représenter un caractère quelconque.
Ce type est un peu plus particulier que les autres, d'une part parce que sa taille définit l'unité de calcul pour les quantités de mémoire (et donc pour les tailles des autres types du langage) et d'autre part son domaine de valeur peut grandement varier de manière relativement inattendue.
Par définition, la taille du type codice_1, notée codice_66, vaut toujours 1. Cependant, il faut faire attention : contrairement à ce qu'on pense souvent, un codice_1 au sens du C ne vaut pas toujours un octet. Il occupera au minimum 8 bits, mais il existe des architectures, relativement spécialisées il est vrai, ayant des codice_1 de 9 bits, de 16 bits, voire plus. Même si, dans une large majorité des cas, les compilateurs utilisent des codice_1 de 8 bits, à la fois par simplicité (les machines modernes fonctionnent généralement en 8, 16, 32 ou 64 bits) et pour éviter des problèmes de portabilité de code (beaucoup de codes C existants reposent sur l'hypothèse que les codice_1 font 8 bits, et risqueraient de ne pas marcher sur une autre architecture). Par simplification, nous utiliserons donc le terme "octet" la plupart du temps dans la suite de ce wikilivre.
Un autre piège de ce type est qu'il peut être de base (c'est-à-dire implicitement) codice_10 ou codice_11, au choix du compilateur, ce qui peut s'avérer dangereux (c'est-à-dire difficile à maitriser). Considérez le code suivant :
/* Ce code peut ne pas fonctionner avec certains compilateurs */
char i;
for (i = 100; i >= 0; i --)
 /* ... */
Dans cet exemple, l'instruction codice_73 permet de faire itérer les valeurs entières de codice_74 de 100 à 0, incluses. On pourrait naïvement penser optimiser en utilisant un type codice_1. Sauf que si ce type est implicitement codice_11, la condition codice_77 sera toujours vraie, et tout ce que vous obtiendrez est une boucle infinie. Normalement, tout bon compilateur devrait vous avertir que la condition est toujours vraie et donc vous permettre de corriger en conséquence, plutôt que perdre des heures en débugage.
Constantes représentant un caractère.
Une constante représentant un caractère (de type char) est délimitée par des apostrophes, comme par exemple codice_78. En fait le langage C n'a initialement pas été conçu pour utiliser tous les caractères. Le type char permet de représenter ni plus ni moins que des nombres entiers (ils sont de type codice_4, mais leur valeur tiendra dans un type codice_1), les deux étant parfaitement interchangeables. Cependant, comme dit plus haut, il ne s'agit généralement pas là des caractères Unicode que nous manipulons tous les jours, mais de caractère-octet dont la portée est réduite.
Un petit exemple :
int main(void)
 printf("Sur votre machine, la lettre 'a' a pour code %d.\n", 'a');
 return 0;
Le programme précédent donnera le résultat suivant dans un environnement ASCII :
Il est tout à fait autorisé d'écrire codice_81 ou codice_82. 
Cette soustraction permet de convertir une minuscule ASCII en majuscule si le codage ASCII est utilisé, mais ne le permet pas si un autre codage est utilisé (comme ISO-8859-1 ou UTF-8).
Valeur des caractères-octets.
La valeur représentée par cette constante est néanmoins dépendante des conventions de codages de caractères employées. À l'origine ces conventions étaient connues du système ; aujourd'hui, même si dans une écrasante majorité des cas, on se retrouvera avec un jeu de caractères augmentant l'ASCII et donc l'ISO-646. 
Le code ASCII définit 96 glyphes de caractères portant les numéros 32 à 126, bien loin des milliers de caractères nécessaires pour les logiciels fonctionnant sur la planète entière et dans de nombreuses langues. Cet ensemble est à peine suffisant pour couvrir l'anglais alors que plusieurs langues latines étaient visées à l'époque où l'ASCII et l'ISO-646 ont été définis, si bien que de nombreuses extensions sont par la suite apparues.
Par exemple le caractère « œ » (ligature du o et du e) a pour valeur :
Retenons simplement qu'Unicode est omniprésent sur Internet, mais que des logiciels plus anciens ou embarqués peuvent fonctionner avec des jeux de caractères huit bits, plus limités. Il s'agit en fait d'une problématique concernant des sujets plus vastes, comme l' "internationalisation", la "portabilité" et l' "interopérabilité".
Le langage C reste relativement abstrait à ce niveau : le type char contient généralement un octet et les chaînes, une simple suite d'octets terminée par 0. Il laisse au système et au développeur le soin d'interpréter et de traiter les octets comme il se doit. Ceci peut être fait à l'aide de bibliothèques appropriées. Si on trouve ici ou là de telles listes de bibliothèques , il est préférable de connaître le langage C avant de les utiliser.
Cet abstraction du langage C lui a permis de s'adapter aux nombreuses évolutions des conventions de codages des caractères.
Caractères non graphiques.
Certains caractères ne sont pas graphiques. Par définition, on ne peut pas donc les écrire dans un code source de manière visible.
Le langage C adopte la convention suivant pour désigner certains d'entre eux de manière littérale :
De plus, on peut écrire n'importe quelle valeur de caractère avec les expressions suivantes :
Trigramme.
Le langage C date d'une époque où le standard de codage des caractères était l'ISO-646, un standard encore plus ancien et plus incomplet que l'ASCII. Les caractères absent de l'ISO-646 pouvaient être simulés par une séquence de trois caractères.
L'ASCII s'étant répandu, cette fonctionnalité tombée en désuétude est en général à éviter, car très souvent inutile, et peut causer des bugs incompréhensibles au programmeur non averti. Néanmoins, de très rares programmes peuvent utiliser ce genre de fonctionnalités. Un trigramme est simplement une suite de trois caractères dans le code source qui sera remplacée par un seul.
Cette fonctionnalité a été ajoutée au C pour supporter les architectures (systèmes) dont l'alphabet ne dispose pas de certains caractères qui sont nécessaires dans la syntaxe du C, comme les dièses ou les accolades.
Les substitutions suivantes sont faites partout dans le code source (y compris les chaînes de caractères) :
Voici une manière de rendre illisible un programme utilisant les trigrammes :
??=include <stdio.h>
int main(void)
 puts("Bonjour !");
 return 0;
Par défaut, la plupart des compilateurs désactivent les trigrammes, au cas où vous ne seriez pas encore dissuadé de les utiliser.
Chaîne de caractères.
Une chaîne de caractère, comme son nom l'indique, est une suite de caractères avec la particularité d'avoir un caractère nul (0) à la fin. Une chaîne de caractère est en fait implémentée en C avec un tableau de type codice_1.
Ce chapitre vous donne les rudiments sur les chaînes de caractère pour une première approche.
Pour en savoir plus sur
 Programmation_C/Tableaux#Chaînes_de_caractères
Structure.
En mémoire, une chaîne de caractère est représenté dans le langage C comme un tableau d'octet dont les valeurs dépendent de l'encodage utilisé ici, Unicode.
Chaîne littérale.
On appelle une chaîne littérale la manière dont est définie une constante chaîne dans un code source.
Sous sa forme la plus simple, on déclare une chaîne comme une suite de caractères entre guillemets (double quote) :
"Ceci est une chaîne de caractère";
""; /* Chaîne vide */
Si la chaîne est trop longue, on peut aussi la couper sur plusieurs lignes :
"Ceci est une chaîne de caractère, " /* pas de ; */
"déclarée sur plusieurs lignes.";
Deux chaînes côtes à côtes (modulo les espaces et les commentaires) seront concaténées par le compilateur. De plus on peut utiliser le caractère barre oblique inverse (\) pour annuler la signification spéciale de certains caractères ou utiliser des caractères spéciaux (C.f liste ci-dessus).
"Une chaîne avec des \"guillemets\" et une barre oblique (\\)\n";
Il est aussi possible d'utiliser la notation hexadécimale et octale pour décrire des caractéres dans la chaîne, il faut néanmoins faire attention avec la notation hexadécimale, car la définition peut s'étendre sur plus de 2 caractéres. En fait, tous les caractères suivant le codice_92 et appartenant à l'ensemble codice_93 seront utilisés pour déterminer la valeur du caractère (du fait que les caractères d'une chaîne peuvent faire plus qu'un octet). Cela peut produire certains effets de bords comme :
/* Ce code contient un effet de bord inattendu */
"\x00abcdefghijklmnopqrstuvzxyz"
Ce code n'insèrera pas un caractère 0 au début de la chaine, mais toute la séquence codice_94 servira à calculer la valeur du caractère (même si le résultat sera tronqué pour tenir dans un type codice_1). On peut éviter cela en utilisant la concaténation de chaînes constantes :
"\x00" "abcdefghijklmnopqrstuvzxyz"
Enfin, les chaînes de caractères faisant appel aux concepts de pointeur, tableau et de zone mémoire statique, leur utilisation plus poussée sera décrite dans la section dédiée aux tableaux.
À noter la représentation obsolète des chaînes de caractères multilignes. À éviter dans la mesure du possible :
/* Ce code est obsolete et a eviter */
"Ceci est une chaîne de caractère,\
déclarée sur plusieurs lignes";
Booléens.
Le langage (jusqu'à la norme C99) ne fournit pas de type booléen. La valeur entière 0 prend la valeur de vérité "faux" et toutes les autres valeurs entières prennent la valeur de vérité "vrai".
La norme C99 a introduit le type codice_96, qui peut contenir les valeurs 0 et 1. Elle a aussi ajouté l'en-tête codice_97, qui définit le type codice_98 qui est un raccourci pour codice_96, et les valeurs codice_100 et codice_101. Néanmoins, ces nouveautés du C99 ne sont pas très utilisées, les habitudes ayant été prises d'utiliser 0 et "différent de zéro" pour les booléens en C.
Nota : toute expression utilisant des opérateurs booléens (voir opérateurs), retourne 1 si l'expression est vraie et 0 si elle est fausse, ce qui rend quasiment inutile l'usage du type booléen.
Un booléen en un entier ont des règles de conversion différente, une valeur flottante comprise entre 0 et 1 non inclus, n'aura pas la même valeur selon que le récipient soit booléen ou entier. La valeur flottante NaN, étant différente de 0 sera vraie dans les deux cas.
Vide.
En plus de ces types, le langage C fournit un autre type, codice_102 qui représente "rien", le "vide". Il n'est pas possible de déclarer une variable de type codice_102. Nous verrons l'utilité de ce type lorsque nous parlerons de fonctions et de pointeurs.