-
Notifications
You must be signed in to change notification settings - Fork 16
/
stdio.txt
435 lines (418 loc) · 28.6 KB
/
stdio.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
STDIO.H
FILE #Le type FILE est en fait un struct, implémentée de
#diverses manières.
#En général, on manipule des pointeurs de FILE qui sont
#renvoyées par des fonctions comme fopen, et dont on
#alimente d'autre fonctions demandant un FILE.
#Les fonctions ouvrant un FILE ouvrent en général aussi
#un buffer avec.
#La struct contient un file position indicator de type
#fpos_t indiquant l'endroit où lire et écrire. Le file
#position indicator ne peut pas toujours être déplacé.
#Il est déplacé à chaque octet lu/écrit
#Elle contient aussi des flags indiquant si une erreur
#a été rencontrée, ou si on se trouve à EOF.
#FILE peut être un fichier spécial
#Les file descriptors contiennent eux-même un file
#position indicator, des flags, etc., mais pas de buffer
#Un channel est un file descriptor ou un FILE
fpos_t #Type d'un file position indicator (en général un long
#int, c'est pourquoi on ne peut pas en théorie ouvrir
#des fichiers de plus de 2GB sur un système 32 bits)
stdin #FILE_ADR créé par défaut à la création de tout programme
#(entrée standard). Il est alloué par le système, et
#peut être redirigé par lui (avec les redirections Bash
#par exemple)
stdout #Même chose, mais sortie standard
stderr #Même chose, mais erreur standard
EOF #Macro (valant souvent -1), renvoyé par plusieurs
#fonctions pour indiquer la fin d'un stream
FILENAME_MAX #Nombre de caractères maximal dans un nom de fichier
FOPEN_MAX #Nombre de streams pouvant être ouverts en même temps
#(en général 8 ou 16)
P_tmpdir #STR désignant le répertoire temporaire, utilisé par
#tmpnam() ou tmpfile() ("/tmp" pr exemple)
L_tmpnam #Nombre minimal de caractères d'un fichier temporaire,
#utilisé par tmpnam()
TMP_MAX #Nombre de fichiers temporaires pouvant être créés par
#tmpnam()
fopen(STR1, STR2) ----# Renvoie un FILE_ADR pointant vers le fichier se
| trouvant au chemin STR1, en fonction du mode STR2,
| avec un full-buffer, sauf si lié à un terminal
| interactif, auquel cas, line-buffer
| FILE devra ensuite être fermé. Si FILE n'existe pas,
| et que le mode n'est pas "r" ou "r+", le créé. Le file
| position indicator est placé en fonction du mode.
| Les modes possibles sont :
| - "r" : lecture seule (sans troncature, et
| impossible de créer un fichier)
| - "r+" : même chose, mais écriture également
| - "w" : écriture seule (troncature si fichier
| existe, création du fichier sinon)
| - "w+" : même chose, mais en lecture également
| - "a" : écriture seule (sans troncature, file
| position indicator au début du fichier,
| mais inutilisé, et écriture toujours à la
| fin du fichier ; création du fichier s'il
| n'existe pas)
| - "a+" : même chose, mais en lecture également
| (écriture à la fin du fichier, et lecture
| en fonction du file position indicator)
| Il est possible de rajouter "t" ou "b" ou deuxième ou
| troisième lettre pour indiquer s'il faut le considérer
| comme un fichier texte ou binaire, mais ce n'est pas
| pertinent sous Linux
| Dans les modes avec un +, il est nécessaire entre une
| lecture et une écriture sur le fichier de faire une
| opération stérile de repositionnement de fichier (tel
| que fseek(FILE_ADR, 0, SEEK_SET)) ou fsetpos(), ou
| faire un fflush()
| Comme extension GNU, il y a aussi ces modes :
| - rajouter un "x" après la lettre du mode fait que
| si le fichier existe, une erreur se produit (ne
| marche pas avec "r" et "r+"
| Ecrire sur un fichier non tronqué remplace les octets
| (et non insert)
| Sur les systèmes 32 bits, il est impossible d'ouvrir
| un fichier de taille > 2 GB avec fopen(). Utiliser
| fopen64()
| Lire un fichier dont tous les caractères ont été lus
| fait en général lire EOF. Il est impossible
| d'atteindre EOF avec une écriture.
| Est en fait un wrapper de open(), et crée par défaut
| le fichier avec les permissions 0666 - l'umask.
| Renvoie NULL en cas d'échec d'ouverture : faire donc
| toujours un :
| if ( (FILE *FICHIER = fopen( ... )) == NULL )
freopen(STR1, STR2, #Ferme FILE et le réouvre en le faisant pointer vers le
FILE_ADR) #chemin STR1, sous le mode STR2.
----| Renvoie le nouveau FILE_ADR ouvert, ou NULL si échec
| Souvent utilisé pour rediriger stdin, stdout ou stderr
| car certains systèmes (non-GNU) ne permettent pas de
| fermer stdin, stdout ou stderr sinon
fclose(FILE_ADR) #Ferme le filedescriptor associé à FILE, flush son
#output, discarde son input buffer, et ferme les deux
#buffers. Les streams ouverts par un programme sont
#automatiquement fermés à l'extinction du programme par
#ailleurs, et les buffers flushed.
----| 0 si succès, EOF si échec
rename(STR1, STR2) #Déplace (= renomme) un fichier, dont le chemin est STR1
#vers le chemin STR2. Si un fichier STR2 existe déjà,
#il est écrasé (sauf s'il s'agit d'un répertoire
#non-vide
#Les fichiers utilisant le contenu actuel de STR1 ne
#sont pas affectés
#Ne fait rien si STR1 et STR2 sont des hard links vers
#le même contenu
#STR1 et STR2 doivent être sur la même partition
----| 0 si succès, EOF si échec
remove(STR) #Supprime un fichier, dont le chemin est STR, en
#appelant unlink() ou rmdir().
#Le contenu du fichier lui-même peut encore être utilisé
#par les processes l'utilisant actuellement, mais ne le
#sera plus une fois que plus aucun process ne
#l'utilisera.
#Ne déréférence pas les symlinks
----| 0 pour un succès, -1 si échec
tmpfile(void) ----# Ouvre et renvoie un FILE_ADR temporaire, qui sera
| supprimé lors de la cloture, ou de la fermeture du
| programme. Le fichier est créé dans :
| 1) P_tmpdir
| 2) /tmp
tmpnam(STR) #Remplace STR par un chemin de fichier temporaire
#aléatoire : ce chemin de fichier commence par P_tmpdir
#(exemple : "/tmp/fileAgfPX"). STR doit avoir une taille
#d'au moins L_tmpnam éléments.
#STR peut être NULL, auquel cas, rien n'est remplacé,
#mais la valeur est quand même renvoyée
#tmpnam() peut générer TMP_MAX noms différents.
----| Renvoie ce même chemin de fichier temporaire, sous la
| forme d'une STR.
| Il est possible d'exploiter le fait qu'il y ait un
| délai entre la création du nom de fichier temporaire,
| et la création du fichier temporaire, en créant ce
| dernier entre-deux : utiliser donc tmpfile() ou (moins
| portable) mkstemp()
printf(STR[, VAL]...) #Equivaut à fprintf(stdout, STR[, VAL]...)
fprintf(FILE_ADR, STR #Imprime STR vers FILE.
[, VAL]...) #STR peut contenir des séquences d'échappement backslash
#ainsi que des séquences sous la forme :
# - %[FLAG][WIDTH][PRECISION]LETTRE
#Chacune de ces séquences est remplacée par la VAL qui
#suit.
#LETTRE :
# - %c fait référence au caractère ASCII, tandis que
# tous les %hh... font référence au nombre
# - %d et %i sont équivalents et font référence à un
# signed TOUINT
# - %x et %X convertissent en hexadécimal (avec un 'x'
# ou un 'X' si utilisé avec le flag #) un TOUINT
# - %o convertit en octal un TOUINT
# - %u convertit en unsigned TOUINT
# - %e et %E convertissent avec un exponent (avec un
# 'e' ou un 'E' si utilisé avec le flag #) un
# TOUFLOAT
# - %a et %A est pareil, mais en hexadécimal (C99)
# - %f et %F fait référence à un TOUFLOAT avec une
# notation à virgule
# - %g et %G est égal à %e ou %E si l'exponent est
# supérieur à 3, et à %f, en enlevant les trailing
# zeros sinon
# - Rajouter hh avant d, i, x, X, o ou u fait référence
# à un CHAR
# - Rajouter h avant d, i, x, X, o ou u fait référence
# à un SHORT
# - Ne rien rajouter avant d, i, x, X, o ou u fait
# référence à un INT
# - Rajouter t avant d, i, x, X, o ou u fait référence
# à un PTRDIFF_T (C99)
# - Rajouter z ou Z avant d, i, x, X, o ou u fait
# référence à un SIZE_T (C99, Z est déprécié)
# - Rajouter l avant d, i, x, X, o ou u fait référence
# à un LONG
# - %D signifie %ld, %O %lo et %U %lu, mais déprécié
# - Rajouter ll avant d, i, x, X, o ou u fait référence
# à un LONG_LONG
# - Ne rien rajouter avant e, E, a, A, f, F, g ou G
# fait référence à un FLOAT
# - Rajouter l avant e, E, a, A, f, F, g ou G fait
# référence à un DOUBLE
# - Rajouter L avant e, E, a, A, f, F, g ou G fait
# référence à un LONG_DOUBLE
# - Rajouter j avant d, i, x, X, o ou u fait référence
# à un INTMAX_T ou à un UINTMAX_T (C99)
# - %s est une STR
# - %ls ou %S est une WSTR, %lc ou %C un WCHAR (%S et
# %C sont dépréciés)
# - %p est un VOID*, dont l'adresse, et non ce qu'elle
# pointe, est présenté sous la forme hexadécimale
# - %n attend alors un INT_ADR, dans lequel sera
# enregistré le nombre de caractères imprimés
# jusqu'ici.
# - %m imprime le résultat de strerror(errno) (pas
# d'argument requis) (extension GNU)
#WIDTH désigne le nombre minimum de caractères imprimés
#(le padding par défaut est avec des espaces, vers la
#gauche)
#PRECISION commence par un point, suivi d'un nombre qui
#désigne :
# - le nombre de décimales pour un %e, %E, %f ou %F
# - le nombre de chiffres maximal pour un %g ou %G
# - le nombre de caractères maximum pour un %s
# - le nombre de chiffres minimal pour un TOUINT
#Si seul un . est présent, PRECISION est 0
#Un * peut être utilisé à la place du nombre de WIDTH ou
#de PRECISION, et sera remplacé par le prochain VAL (qui
#précéderont donc la VAL principale)
#FIELD peut être :
# - # pour :
# - avec %x ou %X, rajouter 0x ou 0X devant
# - avec %o, rajouter 0 devant
# - avec un TOUFLOAT, met toujours la virgule
# décimale
# - avec %g et %G, les trailing zeros ne sont pas
# supprimés
# - 0 : fait le padding avec des 0
# - - : aligne à gauche
# - + : un + est rajouté devant les nombres positifs
# - (espace) : un espace est rajouté devant les
# nombres positifs
# - ' : groupe les milliers en fonction de LC_NUMERIC
# (extension GNU)
# - I : écrit les nombres entiers en fonction de
# LC_NUMERIC (par exemple nombres persans)
# extension GNU)
#Il est possible de choisir la VAL que l'on veut pour
#une séquence donnée (et donc choisir plusieurs fois la
#même VAL), et un field donné (PRECISION, WIDTH, ou la
#valeur générale) en faisant :
# - suivre .PRECISION de NOMBRE$
# - suivre WIDTH de NOMBRE$
# - suivre % de NOMBRE$ (pour la valeur générale)
#où NOMBRE est la place de la VAL parmi toutes les VAL
#(commence à l'index 1). Cette notation est seulement
#Unix. NOMBRE est au maximum NL_ARGMAX
#Attention à bien assigner un TOUFLOAT à un %e, etc.,
#sinon ça bugue (rajouter un .0 devant un entier)
#Les nombres sont imprimés en fonction des locales
----| Renvoie le nombre de caractères imprimés (sans le
| '\0') ou un nombre négatif en cas d'échec
sprintf(STR1, STR2 #Equivaut à fprintf, mais remplace plutôt le contenu de
[, VAL]...) #STR1 par STR2. STR1 doit avoir de la mémoire allouée.
#VAL ne doit pas overlap STR1. Dangereux, car risque de
#buffer overflow : utiliser snprintf ou asprintf()
----| Renvoie le nombre de caractères imprimés (sans le
| '\0') ou un nombre négatif en cas d'échec
vprintf(STR, #Equivaut à printf, fprintf et sprintf, sauf que les
VA_LIST_VAR) #VAL... sont celles d'une VA_LIST_VAR (inclure donc
vfprintf(FILE_ADR, STR, #<stdarg.h>). Elle doit être intialisée avec un va_start
VA_LIST_VAR) #ou un va_copy, et son contenu n'est pas modifié, il
vsprintf(STR1, STR2, #faudra donc appeler va_end.
VA_LIST_VAR) ----| Renvoie le nombre de caractères imprimés (sans le
| '\0') ou un nombre négatif en cas d'échec
scanf(STR[, ADR]...) #Equivaut à fscanf(stdin, STR[, ADR]...)
fscanf(FILE_ADR, STR #STR est une suite de caractères que la lecture de FILE
[, ADR]...) #doit matcher. FILE est lu d'autant de caractères que
#ce qu'il matche avec STR.
#STR peut contenir :
# - des espaces, qui peuvent matcher dans FILE toute
# suite (dont aucun) de blanks
# - des caractères, pris littéralement
# - des specifiers, qui enregistrent ce qui est lu dans
# FILE dans le prochain ADR. Si le specifier ne
# matche pas, NULL est renvoyé à ADR, et la lecture
# s'arrête.
#Les spécifiers sont comme pour printf :
# - mêmes LETTRE, sauf que :
# - %s arrête sa lecture au premier whitespace, et
# skippe les leading whitespaces
# - %c non, et peut lire plusieurs caractères si un
# WIDTH est précisé
# - %[LETTRES] est comme %c, mais seuls les LETTRES
# indiquées sont possibles. Les ranges du style
# a-z sont possibles, les négations avec ^ aussi
# (ce qui permet de lire tout caractère, mais au
# moins une LETTRES doit être entrée). Les classes
# POSIX sont impossibles, mais les séquences
# d'échappement backslash oui.
# - %n marche pareil
# - FLAG et PRECISION inexistants
# - WIDTH indique le nombre de caractères maximal
# attendus
# - Si un * suit le %, le specifier est lu dans FILE,
# mais n'est enregistré dans aucun ADR
#%s et %[LETTRES] notamment peuvent provoquer des
#buffer overflows : il est possible (extension GNU) de
#rajouter un "a" après le %. Le specifier doit alors
#être de type char** (sizeof(char*) octets doivent être
#alloué tout de même), et scanf allouera automatiquement
#la mémoire pour enregistrer la STR, via malloc()
----| Retourne le nombre d'ADR ayant reçu un specifier, ou
| EOF en cas de fin de lecture, ou en cas d'erreur
| Peut causer un bufferoverflow : à éviter
sscanf(STR1, STR2 #
[, ADR]...) #Comme fscanf, mais utilise STR1 plutôt que FILE.
gets(STR) #Remplace STR par stdin, jusqu'à la première newline
#(non incluse) ou EOF (non inclus).
----| Renvoie ce dernier, ou NULL si erreur.
| A éviter car risque de buffer overflow : utiliser
| fgets(), fgetc() ou getline()
fgets(STR, INT_VAL, #Remplace STR par les INT_VAL - 1 premiers caractères de
FILE_ADR) #FILE, où s'arrête à la première newline (incluse) ou
#EOF (non inclus).
----| Renvoie ces derniers, ou NULL si erreur ou EOF. A ne
| pas utiliser donc si STR est susceptible de contenir
| des '\0' (contrairement à fread() et getline(), voir
| ces fonctions pour comprendre ; on peut aussi utiliser
| une boucle while avec fgetc())
getchar(void) #Equivaut à getc(stdin)
fgetc(FILE_ADR) #Lit le prochain caractère de FILE
----| Renvoie ce caractère sous forme d'un unsigned int, ou
| EOF si erreur, ou fin de fichier
getc(FILE_ADR) #Equivaut à fgetc, mais est une macro : préférer fgetc()
ungetc(CHAR_VAL, #Déplace le file position descriptor d'un caractère en
FILE_ADR) #arrière de FILE, et place CHAR_VAL dans son input
#buffer.
#L'idée est que lorsque l'on teste caractère après
#caractère un fichier, pour s'arrêter à la rencontre
#d'un caractère précis, on s'arrête hélas juste après :
#pour pouvoir tout de même relire ce caractère, on peut
#faire ungetc().
#Cependant, il est aussi possible de placer dans
#l'input buffer un autre caractère que celui que l'on
#cherchait
#Un fflush() ou fseek() avant la prochaine tentative de
#lecture, ignorera donc l'effet d'ungetc(), puisque
#flushera l'input buffer.
#Ne peut être fait qu'une fois avant une nouvelle
#tentative de lecture de FILE
----| Renvoie CHAR_VAL, ou EOF si erreur.
puts(STR) #Equivaut à fputs(STR, stdout), sauf que cela ajoute une
#newline.
fputs(STR, FILE_ADR) #Imprime STR vers FILE.
----| Renvoie un nombre non-négatif si succès, EOF sinon.
| Attention, tronquera STR si STR a un '\0' en son sein
| utiliser donc fwrite() couplé avec getline() ou
| fread()
putchar(INT_VAL) #Equivaut à putc(INT_VAL, stdout)
fputc(INT_VAL, FILE_ADR)#Imprime le caractère désigné par INT_VAR (ASCII) dans
#FILE
----| Renvoie le caractère imprimé, sous forme d'INT_VAL, ou
| EOF en cas d'erreur
putc(INT_VAL, FILE_ADR) #Equivaut à fputc, mais est une macro : préférer fputc()
fread(ADR, SIZE_T_VAR1, #Lit SIZE_T_VAR2 éléments de SIZE_T_VAR1 octets de FILE
SIZE_T_VAR2, FILE_ADR) #et écrit le résultat (mais ne tronque pas) à partir de
#ADR. Arrête sa lecture si EOF rencontré, mais ne
#renvoie 0 (pour cause d'EOF) que si aucun caractère
#n'a été lu (donc après un nouvel appel)
----| Renvoie le nombre d'octets bien lus : si ADR est une
| STR, utiliser ce nombre d'octets avec fwrite() pour
| imprimer STR plutôt que d'imprimer "normalement" STR
| avec puts() par exemple, permet d'éviter de tronquer
| STR lors de l'impression s'il contenait des null
| characters avant le '\0' final
| Renvoie 0 si erreur ou EOF (pour distinguer,
| utiliser feof() et ferror())
fwrite(ADR, SIZE_T_VAR1,#Lit SIZE_T_VAR2 éléments de SIZE_T_VAR1 octets à partir
SIZE_T_VAR2, FILE_ADR) #de l'adresse pointée par ADR, et écrit le résultat
#(mais ne tronque pas) dans FILE.
----| Renvoie le nombre d'octets bien lus
feof(FILE_ADR) ----# Renvoie 0 si EOF a été atteint dans FILE, et != 0
| sinon.
ferror(FILE_ADR) ----# Renvoie 0 si une erreur s'est produite dans la lecture
| ou l'écriture de FILE, et != 0 sinon
clearerr(FILE_ADR) #Supprime l'indicateur d'erreur et d'EOF de FILE, si
#présents
perror(STR) ----# Imprime STR (n'ajoute pas de newline) sur stderr,
| suivi d'un : et d'un espace, si STR n'est pas "" ou
| NULL
| Effectue ensuite un strerror(errno) (même si
| errno == 0) : doit donc être placé juste après le
| soupçon de modification d'errno
| Mettre le nom du programme (voir program_invocation_
| name) dans le message d'erreur si possible
RANDOM ACCESS ERREUR ==>#Si le fichier se trouve sur un support ne supportant
#pas le random access, ftell(), fseek(), etc. renverront
#une erreur
fseek(FILE_ADR, #Positionne le file position descriptor de FILE à
LONG_VAL, INT_VAL) #LONG_VAL (peut être négatif) octets après la position
#spécifiée par INT_VAL. Permet une écriture/lecture
#non-séquentielle (random access). Utiliser une valeur
#renvoyée par ftell() dans LONG_VAL, car certains
#systèmes n'utilisent pas l'octet comme mesure du
#mouvement de fseek sur les text files.
#INT_VAR peut être :
# - SEEK_SET (en général 0) : début du fichier
# - SEEK_CUR (en général 1) : position actuelle
# - SEEK_END (en général 2) : fin du fichier
#Cf ci-dessus les particularités des modes "a" et "a+" :
#en utilisant le flag O_APPEND de open(), ils permettent
#d'éviter des problèmes si deux processes écrivent en
#même temps : à préférer donc à SEEK_END.
#Les buffers sont flushed par ailleurs, et un clearerr()
#est effectué. Préférer fseeko() si available
#Sur Windows, sur les fichiers texte, pour que fseek()
#marche il faut :
# - que soit LONG_VAL soit 0
# - soit SEEK_SET soit utilisé, et LONG_VAL vient d'un
# nombre obtenu, et non modifié, par un précédent
# ftell()
----| Renvoie 0 si succès, -1 sinon
| Préférer fgetpos() et fsetpos() si possible
rewind(FILE_ADR) #Equivaut à fseek(FILE, 0, SEEK_SET), sauf que cela
#fait un clearerr() aussi
ftell(FILE_ADR) ----# Renvoie un LONG_LIT spécifiant la position du file
| position descriptor de FILE, en octets (Sous Unix).
| En dehors d'Unix, s'il s'agi d'un text file, il ne
| s'agit pas vraiment du nombre d'octets, mais cela
| peut être utilisé par fseek comme LONG_VAL. Les
| buffers sont flushed par ailleurs, et un clearerr()
| est effectué. Préférer ftello() si available
| Renvoie -1 sinon
fgetpos(*FILE, # Renvoie la position du file position indicator de FILE
STKTFPOS_T_ADR) ----| sous forme de STKTFPOS_T_ADR.
fsetpos(*FILE, # Déplace le file position indicator de FILE vers la
STKTFPOS_T_ADR) ----| position indiquée par STKTFPOS_T_ADR.
#Cf ci-dessus les particularités des modes "a" et "a+"