printf(3)

Fonction de la bibliothèque C

Écrit du texte mis en forme sur la sortie standard. Les formats à connaître (%d, %ld, %zu, %p, %s), ce que renvoie printf et les warnings -Wformat.

Synopsis
#include <stdio.h>
int printf(const char *restrict format, ...);

Description

printf parcourt son format caractère par caractère. Le texte ordinaire est recopié tel quel ; chaque % introduit une conversion, qui consomme l'argument suivant et l'écrit sous forme de texte. Comme printf accepte un nombre variable d'arguments, il ne connaît pas leur type : c'est le format qui le lui dit, et il doit correspondre exactement.

FormatArgument attendu
%d ou %iint
%u, %xunsigned int, en décimal ou en hexadécimal
%ld, %lldlong, long long
%zusize_t, le type de sizeof et de strlen
%fdouble, ou un float, converti en double à l'appel
%cun caractère, transmis comme un int
%sun char * vers une chaîne terminée par '\0'
%pun void *
%%rien, affiche un %

Le texte ne part pas directement à l'écran : il passe par le tampon de stdout, vidé à chaque \n dans un terminal et par blocs dans un pipe. C'est la raison pour laquelle printf n'affiche rien avant un crash.

Valeur de retour

Le nombre d'octets écrits, ou une valeur négative en cas d'erreur. Des octets, pas des caractères : dans un source en UTF-8, printf("été\n") renvoie 6, chaque « é » en occupant deux.

Pièges

  • Un format qui ne correspond pas au type est un comportement indéfini. -Wall active -Wformat, qui le détecte à la compilation. Pour un sizeof, GCC propose %ld parce que size_t est un unsigned long sur cette machine, mais %zu est la seule écriture portable :

Terminal
$ gcc -Wall -Wextra -g warn.c -o warnwarn.c: In function 'main':warn.c:7:14: warning: format '%d' expects argument of type 'int', but argument 2 has type 'long unsigned int' [-Wformat=]    7 |     printf("%d\n", sizeof notes);      |             ~^     ~~~~~~~~~~~~      |              |     |      |              int   long unsigned int      |             %ld
  • printf(texte), quand texte vient de l'utilisateur, interprète chaque % qu'il contient, et %n permet même d'écrire en mémoire. Écris printf("%s", texte).

  • %p attend un void * : convertis le pointeur, (void *)p.

  • L'exercice fix-the-format te fait corriger un format faux sous -Werror, avec un size_t et un long.

Exemple

formats.c
#include <stdio.h>
int main(void){    int notes[5] = {12, 15, 9, 18, 11};    long total = 6000000000L;    int n;
    n = printf("Yasmine a %d ans\n", 19);    printf("%d octets\n", n);    n = printf("été\n");    printf("%d octets\n", n);    printf("%zu octets à l'adresse %p\n", sizeof notes, (void *)notes);    printf("total : %ld\n", total);    return 0;}
Terminal
$ gcc -Wall -Wextra -g formats.c -o formats$ ./formatsYasmine a 19 ans17 octetsété6 octets20 octets à l'adresse 0xffffe6dfb940total : 6000000000

Le \n compte dans les 17 octets de la première ligne. L'adresse change à chaque exécution.

C

mini_printf

Écris mini_printf, qui développe %c, %s, %d, %x et %% avec write et renvoie le nombre exact d'octets écrits.

Ouvrir l'exercice

À toi d'écrire le code.