Maîtriser les spécificateurs de format en C pour l'embarqué

Les spécificateurs de format sont essentiels pour contrôler la manière dont les données sont affichées ou interprétées par les fonctions d'entrée/sortie, notamment printf et scanf en C. Ils permetttent de spécifier le type de données, l'alignement, la largeur et la précision de la sortie.

Formats de base

  • %d : Entier décimal signé.
  • %o : Entier octal non signé.
  • %x : Entier hexadécimal non signé (lettres minuscules).
  • %X : Entier hexadécimal non signé (lettres majuscules).
  • %c : Caractère unique.
  • %s : Chaîne de caractères.
  • %f : Nombre à virgule flottante (double précision par défaut pour les littéraux flottants).
  • %p : Pointeur (adresse mémoire).

Caractères d'échappement courants

  • \n : Nouvelle ligne.
  • \t : Tabulation horizontale.
  • \a : Alerte sonore (bip).
  • \b : Retour arrière (efface le caractère précédent).
  • \f : Saut de page.
  • \r : Retour chariot (place le curseur au début de la ligne).
  • \v : Tabulation verticale.

Contrôle des types entiers

Les modificateurs de longueur peuvent être utilisés avec les spécificateurs d'entiers pour cibler des types de données spécifiques :

  • h : Pour les types short int (entier court).
  • l : Pour les types long int (entier long).
  • ll : Pour les types long long int (entier très long).
  • u : Pour les types non signés (unisgned).

Exemples :

  • %hd : short int décimal signé.
  • %hu : unsigned short int décimal non signé.
  • %ld : long int décimal signé.
  • %lu : unsigned long int décimal non signé.
  • %lld : long long int décimal signé.
  • %llu : unsigned long long int décimal non signé.

Exemple de code pour les entiers

#include <stdio.h>

   int main() {
       int signed_int = 100;
       unsigned int unsigned_int = 200;
       short signed_short = 300;
       unsigned short unsigned_short = 400;
       long signed_long = 500;
       unsigned long unsigned_long = 600;
       long long signed_long_long = 700;
       unsigned long long unsigned_long_long = 800;

       printf("Signed int: %d, Size: %zu bytes\n", signed_int, sizeof(signed_int));
       printf("Unsigned int: %u, Size: %zu bytes\n", unsigned_int, sizeof(unsigned_int));
       printf("Signed short: %hd, Size: %zu bytes\n", signed_short, sizeof(signed_short));
       printf("Unsigned short: %hu, Size: %zu bytes\n", unsigned_short, sizeof(unsigned_short));
       printf("Signed long: %ld, Size: %zu bytes\n", signed_long, sizeof(signed_long));
       printf("Unsigned long: %lu, Size: %zu bytes\n", unsigned_long, sizeof(unsigned_long));
       printf("Signed long long: %lld, Size: %zu bytes\n", signed_long_long, sizeof(signed_long_long));
       printf("Unsigned long long: %llu, Size: %zu bytes\n", unsigned_long_long, sizeof(unsigned_long_long));

       return 0;
   }

Contrôle des nombres à virgule flottante

  • %f : Format décimal standard pour les double (ou float s'il est promu).
  • %lf : Spécifique pour les double en entrée (scanf). Pour la sortie (printf), %f suffit généralement car float est promu en double.
  • %Lf : Pour les long double.
  • %e, %E : Notation scientifique (exposant).
  • %g, %G : Choix automatique entre %f et %e (ou %E) selon la valeur et la précision.

Contrôle de la largeur et de la précision :

  • %W.Pf : Où W est la largeur totale du champ (remplie d'espaces si nécessaire, alignée à droite par défaut) et P est le nombre de chiffres après la virgule.
  • %-W.Pf : Aligné à gauche dans le champ de largeur W.

Exemple de code pour les flottants

#include <stdio.h>

   int main() {
       float f_single = 3.14159f;
       double f_double = 123.456789;
       long double f_long_double = 987.654321L;

       printf("Float (default): %f\n", f_single);
       printf("Float (width 10, precision 2): %10.2f\n", f_single);
       printf("Float (width 10, precision 2, left-aligned): %-10.2f\n", f_single);
       printf("Size of float: %zu bytes\n\n", sizeof(f_single));

       printf("Double (default): %lf\n", f_double);
       printf("Double (width 12, precision 3): %12.3lf\n", f_double);
       printf("Double (width 12, precision 3, left-aligned): %-12.3lf\n", f_double);
       printf("Size of double: %zu bytes\n\n", sizeof(f_double));

       printf("Long Double (default): %Lf\n", f_long_double);
       printf("Long Double (width 15, precision 4): %15.4Lf\n", f_long_double);
       printf("Size of long double: %zu bytes\n\n", sizeof(f_long_double));

       // Comparaison de flottants (Attention à la précision !)
       float a = 3.14f;
       double b = 114.114;
       long double c = 6.18L;

       // La comparaison directe peut être trompeuse en raison des erreurs d'arrondi.
       // Littéraux flottants par défaut sont double précision.
       if (a == 3.14f) { // Comparaison avec un littéral float
            printf("a est égal à 3.14f (peut être imprécis)\n");
       } else {
            printf("a n'est pas égal à 3.14f (peut être imprécis)\n");
       }

       if (b == 114.114) { // Comparaison avec un littéral double
            printf("b est égal à 114.114\n");
       } else {
            printf("b n'est pas égal à 114.114\n");
       }
        if (c == 6.18L) { // Comparaison avec un littéral long double
            printf("c est égal à 6.18L\n");
       } else {
            printf("c n'est pas égal à 6.18L\n");
       }


       return 0;
   }

Contrôle des caractères

Le type char est fondamentalement un petit entier (typiquement 1 octet). Il peut être affiché comme un caractère ou comme sa valeur entière.

  • %c : Affiche le caractère correspondant à la valeur ASCII/Unicode.
  • %d : Affiche la valeur décimale du caractère.
  • %o : Affiche la valeur octale du caractère.
  • %x : Affiche la valeur hexadécimale du caractère.
  • %#o : Affiche la valeur octale préfixée par 0.
  • %#x : Affiche la valeur hexadécimale préfixée par 0x.
  • %#X : Affiche la valeur hexadécimale préfixée par 0X.

Exemple de code pour les caractères

#include <stdio.h>

   int main() {
       char char_val = 'A';
       char ascii_code = 66; // Code ASCII pour 'B'
       int int_repr = 67;    // Code ASCII pour 'C'

       printf("char_val as char: %c\n", char_val);
       printf("char_val as int (decimal): %d\n", char_val);
       printf("ascii_code as char: %c\n", ascii_code);
       printf("int_repr as char: %c\n", int_repr); // int_repr est promu en char pour %c
       printf("\n");

       char test_char = 88; // Code ASCII pour 'X'
       printf("Test char ('X'):\n");
       printf("  As char: %c\n", test_char);
       printf("  As decimal: %d\n", test_char);
       printf("  As octal: %o\n", test_char);
       printf("  As hex: %x\n", test_char);
       printf("  As octal with prefix: %#o\n", test_char);
       printf("  As hex with prefix: %#x\n", test_char);
       printf("  As hex (uppercase) with prefix: %#X\n", test_char);

       return 0;
   }

Étiquettes: C printf scanf spécificateurs de format embarqué

Publié le 10 juin à 18h08