Programmation C source/Types de base
int main(void)
 printf("----------------------------------------\n");
 printf(" Entiers\n");
 printf("----------------------------------------\n");
 // Il y a cinq types de variables entières (integer en anglais) :
 char a;
 short int b1; short b2;
 int c;
 long int d1; long d2;
 long long int e1; long long e2; // (ce type a été ajouté depuis la norme C99)
 /* les modificateurs signed et unsigned permettent respectivement
 d'obtenir un type signé ou non signé */
 signed int f;
 unsigned int g;
 /* Domaines de valeurs minimaux des types entiers
 signed char -127 à +127
 unsigned char 0 à +255
 short -32 767 à +32 767
 unsigned short 0 à +65 535
 int -32 767 à +32 767
 unsigned int 0 à +65 535
 long -2 147 483 647 à +2 147 483 647
 unsigned long 0 à +4 294 967 295
 long long -9 223 372 036 854 775 807 à +9 223 372 036 854 775 807
 unsigned long long 0 à +18 446 744 073 709 551 615 */
 // domaine(char) ≤ domaine(short) ≤ domaine(int) ≤ domaine(long) ≤ domaine(long long)
 /* un utilisateur peut connaître les domaines de valeurs exacts
 de sa machine en utilisant l'en-tête <limits.h> */
 printf("\n----------------------------------------\n");
 printf(" Portabilité apportée par C99\n");
 printf("----------------------------------------\n");
 /* certains programmes peuvent nécessiter un type de données de taille fixe
 et cependant être destinés à être portables
 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ù N représente un nombre entier définissant la taille requise en bit
 types implémentés optionnellement sur certaines architectures (à éviter ?)
 uintN_t et intN_t entiers signés ou non de longueur exacte
 intptr_t et uintptr_t entiers pouvant contenir un pointeur
 types requis par toutes les architectures respectant la norme C99
 int_leastN_t et uint_leastN_t
 entiers devant être plus grand que N bits au moins
 int_fastN_t et uint_fastN_t
 entiers rapides à calculer et plus grand que N bits au moins
 intmax_t et uintmax_t
 plus grand entier
 cet en-tête (stdint.h) définit aussi des constantes
 pour les valeurs minimales et maximales de chaque type.
 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) */
 int32_t nombre_de_32_bits_avec_signe = 0;
 printf("Saisir un nombre : ");
 scanf("%" SCNd32, &nombre_de_32_bits_avec_signe);
 printf("Le nombre est %" PRId32 "\n", nombre_de_32_bits_avec_signe);
 printf("\n----------------------------------------\n");
 printf(" Constantes numériques entières\n");
 printf("----------------------------------------\n");
 #if 0
 123
 // un nombre en notation décimale : une suite de chiffres (0-9)
 0123
 /* le caractère « 0 » suivi d'un nombre en notation octale :
 une suite de chiffres compris entre 0 et 7 */
 0x123abc
 /* les caractères « 0x » suivi d'un nombre en notation hexadécimale :
 une suite de chiffres et des lettres a, b, c, d, e, f (ou A, B, C, D, E, F). */
 /* Par défaut, une constante numérique entière est de type int
 si sa valeur est trop grande pour le type int,
 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
 il est recommandé de forcer le type de la constante */
 123U
 // la constante est non-signée
 123L
 // la constante est de type long
 123LL
 // (C99) la constante est de type long long
 123UL
 123ULL
 /* Lorsqu'une constante est suffixée, mais que sa valeur est trop grande
 pour le type demandé, le processus de recherche de type « assez grand »
 est utilisé */
 #endif
 printf("\n----------------------------------------\n");
 printf(" Débordement\n");
 printf("----------------------------------------\n");
 /* Si on essaye d'enregistrer une valeur hors domaine
 dans une variable de type signé, la conversion n'est pas définie par le langage.
 Cela signifie que tout peut arriver. */
 /* Si on essaye d'enregistrer une valeur hors domaine
 dans une variable de type non signé (unsigned long, par exemple),
 la conversion se fait modulo la valeur maximale représentable par ce type + 1 */
 /* On suppose que le type unsigned char est codé sur 8 bits.
 Alors une valeur de ce type peut aller de 0 à 2^8 -1, soit 255 */
 unsigned char h = 300; // 300 - (255 + 1) = 44
 printf("La variable h vaut %hhu.\n", h);
 // %hhu sert à dire à printf() qu'on veut afficher un unsigned char
 h = -5; // -5 + (255 + 1) = 251
 printf("La variable h vaut %hhu.\n", h);
 signed char i = 300; // 300 - (127 + 1) - (127 + 1) = 44
 printf("La variable i vaut %hhd.\n", i);
 // %hhd sert à dire à printf() qu'on veut afficher un signed char
 i = -300; // -300 + (127 + 1) + (127 + 1) = -44
 printf("La variable i vaut %hhd.\n", i);
 /* Sur une telle machine,
 les types signés sont traités de la même manière que les types non signés. */
 /* votre compilateur pourra détecter les débordements
 et vous en avertir (GCC le fait) */
 printf("\n----------------------------------------\n");
 printf(" Réels\n");
 printf("----------------------------------------\n");
 /* Les réels sont approximés par des nombres à virgule flottante
 En voici la liste triée par précision croissante
 float
 double
 long double */
 printf("\n----------------------------------------\n");
 printf(" Constantes réelles\n");
 printf("----------------------------------------\n");
 /* une constante à virgule flottante est
 une suite de chiffres séparée par un caractère point
 cette séparation pouvant s'effectuer à n'importe quel endroit de la suite
 0.0 .0 0. */
 /* ou un nombre suivi d'un caractère e suivi d'un entier
 le nombre peut être soit un entier, soit un réel
 30e-2
 1.002e2 */
 /* Les constantes sont de type double par défaut
 pour un floaf 3.4f ou 3.4F
 pour un long double 3.4l ou 3.4L */
 printf("\n----------------------------------------\n");
 printf(" Arithmétique\n");
 printf("----------------------------------------\n");
 float j = 0;
 int k;
 for (k = 0; k < 1000; k++)
 j += 0.1;
 printf("j = %f\n", j);
 /* Le résultat est 99,999046,
 ce qui montre que la précision du type float est en général mauvaise,
 d'autant plus que le nombre 0,1 n'est pas représentable en binaire.
 Il est ainsi conseillé d'utiliser le type double à la place de float 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 */
 for (k = 1; k < 1001; k++)
 j = k * 0.1;
 printf("j = %f\n", j);
 printf("\n----------------------------------------\n");
 printf(" Caractères\n");
 printf("----------------------------------------\n");
 /* Le type permettant de représenter un caractère est char
 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)
 sizeof(char), vaut toujours 1
 Il occupera au minimum 8 bits, mais il existe des architectures,
 relativement spécialisées il est vrai,
 ayant des char de 9 bits, de 16 bits, voire plus
 Un piège de ce type est qu'il peut être de base signed ou unsigned,
 au choix du compilateur, ce qui peut s'avérer dangereux.
 Ce code peut ne pas fonctionner avec certains compilateurs
 si char est implicitement unsigned, la condition i >= 0 sera toujours vraie */
 char l;
 for (l = 100; l >= 0; l--)
 // ...
 printf("\n----------------------------------------\n");
 printf(" Constantes représentant un caractère\n");
 printf("----------------------------------------\n");
 /* exemple 'a' 'b' 'c'
 En fait pour le C, les caractères ne sont ni plus ni moins que
 des nombres entiers. Il est tout à fait autorisé d'écrire 'a' * 2 ou 'a' - 32
 La valeur représentée par cette constante est néanmoins dépendante du système,
 même si dans une écrasante majorité des cas, on se retrouvera avec un jeu de
 caractére compatible avec ASCII, qui définit précisément les glyphes des
 caractères de 0 à 127
 Cet ensemble est à peine suffisant pour couvrir certaines langues latines,
 seule optique visée à l'époque où il a été défini, si bien que de nombreuses
 extensions sont par la suite apparues
 Il s'agit de l'internationalisation. Le langage C reste relativement agnostique
 à ce niveau : les caractères sont des nombres et les chaînes, une simple suite
 de caractères terminée par 0.
 Au système d'interpréter les nombres comme il se doit. */
 printf("Sur votre machine, la lettre 'a' a pour code %d.\n", 'a');
 printf("\n----------------------------------------\n");
 printf(" Caractères spéciaux\n");
 printf("----------------------------------------\n");
 /* '\" une apostrophe
 '\"' un guillemet
 '\?' un point d'interrogation
 '\\' un backslash
 '\a' un signal sonore (ou visuel)
 '\b' un espace arrière
 '\f' saut au début de la page suivante
 '\n' saut de ligne
 '\r' un retour chariot
 '\t' une tabulation
 '\v' une tabulation verticale */
 /* De plus, on peut écrire n'importe quelle valeur de caractère
 avec les expressions suivantes :
 '\xHH', où chaque H représente un chiffre hexadécimal
 correspondant au code du caractère.
 Par exemple, '\x61' représente le caractère 'a' (minuscule) en ASCII
 (car 97 = 6 * 16 + 1) ;
 '\oOO', où chaque O représente un chiffre octal
 correspondant au code du caractère. */
 printf("\n----------------------------------------\n");
 printf(" Trigramme\n");
 printf("----------------------------------------\n");
 /* 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 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 */
 ??( [
 ??< {
 ??/ \
 ??! |
 printf("\n----------------------------------------\n");
 printf(" Chaîne de caractères\n");
 printf("----------------------------------------\n");
 #if 0
 "Ceci est une chaîne de caractère"
 "" // Chaîne vide
 "Ceci est une chaîne de caractère, " // pas de ;
 "déclarée sur plusieurs lignes."
 "une " "chaine"
 "Une chaîne avec des \"guillemets\" et une barre oblique (\\)\n"
 "\x00abcdefghijklmnopqrstuvzxyz"
 /* il faut faire attention avec la notation hexadécimale,
 car la définition peut s'étendre sur plus de 2 caractéres
 Ce code contient un effet de bord inattendu */
 "\x00" "abcdefghijklmnopqrstuvzxyz"
 "Ceci est une chaîne de caractère,\
 déclarée sur plusieurs lignes";
 // Ce code est obsolete et a eviter
 #endif
 printf("\n----------------------------------------\n");
 printf(" Booléens\n");
 printf("----------------------------------------\n");
 // Le langage (jusqu'à la norme C99) ne fournit pas de type booléen.
 /* on avait jusqu'à présent
 0 faux
 autres valeurs vrai */
 /* en C99 on a le type _Bool, une variable de type _Bool contient 0 ou 1
 l'entete stdbool.h définit bool un raccourci pour _Bool
 ainsi que false et true */
 printf("\n----------------------------------------\n");
 printf(" Vide\n");
 printf("----------------------------------------\n");
 /* void qui représente rien, le vide.
 Il n'est pas possible de déclarer une variable de type void.
 Nous verrons l'utilité de ce type lorsque nous parlerons
 de fonctions et de pointeurs. */
 return 0;