« Programmation C/Entrées/sorties » : différence entre les versions

Contenu supprimé Contenu ajouté
DannyS712 (discussion | contributions)
m <source> -> <syntaxhighlight> (phab:T237267)
Correction (Spécial:LintErrors/misnested-tag + ortho)
Ligne 214 :
* <code>0</code> : Si un zéro est présent dans le spécificateur de largeur, le nombre sera aligné avec zéros au lieu de blancs.
* <code>+</code> : Si un signe plus est présent avec le spécificateur de largeur, le signe du nombre sera affiché tout le temps (0 est considéré comme positif).
* <code>&nbsp;</code> (espace) : Si le nombre est positif, un blanc sera mis avant, pour l'aligner avec les nombres négatifs.
Exemples :
 
Ligne 236 :
=== Spécifier la taille de l'objet ===
 
Par défaut, les entiers sont présuposésprésupposés être de type <code>int</code>, les réels de type <code>double</code> et les chaineschaînes de caractères de type <code>char *</code>. Il arrive toutefois que les types soient plus grands (et non plus petits à cause de la '''promotion des types''', c.f. paragraphes [[Programmation C Opérateurs#Promotion|opérateurs]] et [[Programmation C Fonctions et procédures#Accès aux arguments|fonction à nombre variable d'arguments]]), le spécificateur de format permet donc d'indiquer la taille de l'objet en ajoutant les attributs suivants ''avant'' le caractère de conversion :
* hh : indique que l'entier est un <code>[un]signed char</code> au lieu d'un <code>[unsigned] int</code> ;
* h : indique que l'entier est de type <code>[unsigned] short</code> au lieu d'un <code>[unsigned] int</code> ;
Ligne 280 :
=== Arguments positionnels ===
 
Il s'agit d'une fonctionnalité relativement peu utilisée, mais qui peut s'avérer très utile dans le cadre d'une application internationnaliséeinternationalisée. Considérez le code suivant (tiré du manuel de <code>gettext</code>) :
 
<syntaxhighlight lang="c">
Ligne 286 :
</syntaxhighlight>
 
<code>gettext</code> est un ensemble de fonctions permettant de manipuler des catalogues de langues. La principale fonction de cette bibliothèque est justement <code>gettext()</code>, qui en fonction d'une chainechaîne de caractère retourne la chainechaîne traduite selon la locale en cours (où celle passée en argument si rien n'a été trouvé).
 
Une traduction en allemand du message précédant, pourrait donner :
<code>"%d Zeichen lang ist die Zeichenkette '%s'"</code>
 
On remarque d'emblée que les spécificateurs de format sont inversés par rapport à la chainechaîne originale. Or l'ordre des arguments passés à la fonction <code>printf()</code> sera toujours le même. Il est quand même possible de s'en sortir avec les arguments positionnels. Pour cela, il suffit d'ajouter à la suite du caractère <code>%</code> un nombre, suivi d'un signe <code>$</code>. Ce nombre représente le numéro de l'argument à utiliser pour le spécificateur, en commençant à partir de 1. Un petit exemple :
 
<syntaxhighlight lang="c">
char * s = "Bla bla";
printf("La chaine %2$s a %1$zu caractères\n", strlen(s), s); /* "La chainechaîne Bla bla a 7 caractères" */
</syntaxhighlight>
 
Ligne 310 :
* Flux d'erreur (<code>stderr</code>) : écriture immédiate.
 
C'est ce qui fait qu'un programme affichant des messages à intervalle régulier (genre une seconde), affichent ces lignes une à une sur un terminal, et par bloc de plusieurs lignes lorsqu'on redirige sa sortie vers un programme de mise en page (comme <code>more</code>), avec une latence qui peut s'avérer génantegênante. C'est ce qui fait aussi qu'une instruction comme <code>printf("Salut tout le monde");</code> n'affichera en général rien, car il n'y a pas de retour à la ligne.
 
En fait ce comportement peut être explicitement réglé, avec cette fonction :
Ligne 334 :
La famille de fonctions <code>printf()</code> permet donc de couvrir un large éventail de besoins, au prix d'une pléthore d'options pas toujours faciles à retenir.
 
Il faut aussi faire attention au fait que certaines implémentations de <code>printf()</code> tiennent compte de la localisation pour les conversions des nombres réels (virgule ou point comme séparateur décimal, espace ou point comme séparateurs des milliers, etc.). Ceci peut être gènantgênant lorsqu'on veut retraiter la sortie de la commande. Pour désactiver la localisation, on peut utiliser la fonction <code>setlocale()</code>:
 
<syntaxhighlight lang="c">
Ligne 347 :
== Entrées formatées ==
 
La bibliothèque <code>stdio</code> propose quelques fonctions très puissantes pour saisir des données depuis un flux quelconque. Le comportement de certaines fonctions (<code>scanf</code> notamment) peut paraitreparaître surprenant de prime abord, mais s'éclaircira à la lumière des explications suivantes.
 
<syntaxhighlight lang="c">
Ligne 366 :
=== Format de conversion ===
 
Les fonctions <code>scanf()</code> analysent le spécificateur de format et les données d'entrée, en les comparant caractère à caractère et s'arrêtant lorsqu'il y en a un qui ne correspond pas. À noter que les blancs (espaces, tabulations et retour à la ligne) dans le spécificateur de format ont une signification spéciale : à un blanc de la chainechaîne ''format'' peut correspondre un nombre quelconque de blanc dans les données d'entrée, y compris aucun. D'autres part, il est possible d'insérer des séquences spéciales, commençant par le caractère '%' et à l'image de <code>printf()</code>, pour indiquer qu'on aimerait récupérer la valeur sous la forme décrite par le caractère suivant le '%' :
 
* '''s''' : extrait la chaîne de caractères, '''en ignorant les blancs initiaux et ce jusqu'au prochain blanc'''. L'argument correspondant doit être de type <code>char *</code> et pointer vers un bloc mémoire suffisamment grand pour contenir la chaîne et son caractère terminal.
* '''d''' : extrait un '''nombre décimal signé''' de type <code>int</code>, ignorant les espaces se trouvant éventuellement avant le nombre.
* '''i''' : extrait un '''nombre''' (de type <code>int</code>) hexadécimal, si la chainechaîne commence par "<code>0x</code>", octal si la chainechaîne commence par "<code>0</code>" et décimal sinon. Les éventuels espaces initiaux seront ignorés.
* '''f''' : extrait un '''nombre réel''', en sautant les blancs, de type <code>float</code>.
* '''u''' : lit un '''nombre décimal non-signé''', sans les blancs, de type <code>int</code>.
* '''c''' : lit un '''caractère''' (de type </code>char</code>), y compris un blanc.
* '''[]''' : lit une '''chaîne de caractères''' qui doit faire partie de l'ensemble entre crochets. Cet ensemble est une énumération de caractère. On peut utiliser le tiret ('-') pour grouper les déclarations (comme "<code>0-9</code>" ou "<code>a-z</code>"). Pour utiliser le caractère spécial ']' dans l'ensemble, il doit être placé en ''première position'' et, pour utiliser le tiret comme un caractère normal, il doit être mis à la fin. Pour indiquer que l'on veut tous les caractères sauf ceux de l'ensemble, on peut utiliser le caractère '^' en première position. À noter que <code>scanf</code> terminera toujours la chaîne par 0 et que, contrairement au spécificateur <code>%s</code>, les blancs ne seront pas ignorés.
* '''n''' : Comme pour la fonction <code>printf()</code>, ce spécificateur de format permet de stocker dans l'entier correspondandcorrespondant de type <code>int</code>, le '''nombre de caractères lus''' jusqu'à présent.
 
=== Contraindre la largeur ===
Ligne 432 :
 
=== Conversions muettes ===
La fonction <code>scanf</code> reconnaitreconnaît encore un autre attribut qui permet d'effectuer la conversion, mais sans retourner la valeur dans une variable. Il s'agit du caractère étoile '*', qui remplace l'éventuel attribut de taille.
 
En théorie, la valeur de retour ne devrait pas tenir compte des conversions muettes.
Ligne 447 :
La fonction <code>scanf()</code> n'est pas particulièrement adaptée pour offrir une saisie conviviale à l'utilisateur, même en peaufinant à l'extrême les spécificateurs de format. En général, il faut s'attendre à une gestion '''très rudimentaire''' du clavier, avec très peu d'espoir d'avoir ne serait-ce que les touches directionnelles pour insérer du texte à un endroit arbitraire.
 
Qui plus est, lors de saisie de texte, les terminaux fonctionnent en mode bloc : pour que les données soient transmises à la fonction de lecture, il faut que l'utilisateur confirme sa saisie par entrée. Même les cas les plus simple peuvent poser problèmes. Par exemple, il arrive souvent qu'on ne veuille saisir qu'un caractère pour répondre à une question du genre <code>"Écraser/Annuler/Arrêter ? (o|c|s)"</code>, avant d'écraser un fichier. Utiliser une des fonctions de saisie nécessite de saisir d'abord un caractère, ensuite de valider avec la touche ''entrée''. Ce qui peut non seulement être très pénible s'il y a beaucoup de questions, mais aussi ''risqué'' si on ne lit les caractères qu'un à un. En effet, dans ce dernier cas, si l'utilisateur entre une chainechaîne de plusieurs caractères, puis valide sa saisie, les caractères non lus seront disponibles pour des lectures ultérieures, répondant de ce fait automatiquement aux questions du même type.
 
Il s'agit en fait de deux opérations en apparence simples, mais impossible à réaliser avec la bibliothèque C standard :
Ligne 461 :
== Entrées non formatées ==
 
Pour saisir des chaineschaînes de caractères indépendemmentindépendamment de leur contenu, on peut utiliser les fonctions suivantes :
 
<syntaxhighlight lang="c">
Ligne 469 :
</syntaxhighlight>
 
La fonction <code>fgets()</code> permet de saisir une ligne complète dans la zone mémoire spécifiée, en évitant tout débordement. Si la ligne peut être contenue dans le bloc, elle contiendra le caractère de saut de ligne (<code>'\n'</code>), en plus du caractère nul. Dans le cas contraire, la ligne sera tronquée, et la suite de la ligne sera obtenue à l'appel suivant. Si la fonction a pu lire au moins un caractère, elle retournera la chainechaîne transmise en premier argument, ou <code>NULL</code> s'il n'y a plus rien à lire.
 
Un exemple de lecture de ligne arbitrairement longue est fournie dans le livre [[Exercices en langage C/Fonctions#Lire une ligne longue avec fgets|Exercices en langage C]] (énnoncéénoncé et solution).
 
La fonction <code>fgetc()</code> permet de ne saisir qu'un caractère depuis le flux spécifié. À noter que la fonction renvoie bien un entier de type <code>int</code> et non de type <code>char</code>, car en cas d'erreur (y compris la fin de fichier), cette fonction renvoie <code>EOF</code> (défini à -1 en général).