En vrai je me posais surtout la question dans le cas de l'héritage, le reste c'était que pour avoir confirmation, mais j'pense que j'vais tout inclure effectivement.
tu voulais pas plutot utiliser write ?
ah oui c'est write() pas print() en effet kaTk
Et pourquoi c'est sale printf?
parce que c'est pas code maison je dirais, moi-meme ca me fait mal au coeur de l'utiliser apres un mois de piscine a 42
tiens je viens de remarquer que LGV est passe modo, j'ai eu un bon mois d'absence
Le 08 août 2016 à 08:38:20 rangerprice a écrit :
Le 08 août 2016 à 04:11:35 whiteapplex a écrit :
Le 08 août 2016 à 04:10:16 rangerprice a écrit :
Au passage il faudrait changer le titre du topic en "print(1, "blabla", 6);" car utiliser printf comme ça c'est saleEt le "1" il est pas sale ?
Si ça te dit pas trop on peut écrire "print(STDOUT, "blabla", 6);" et imaginer qu'il y a un préprocesseur derrière qui initialise STDOUT à 1
Mais les initiés savent déjà que 1 = stdout, seul les vrais comprendront et c'est bien comme ça:hap:
les constantes (pour les fd donc int) STDOUT STDERR et STDIN existent déjà dans stdio.h
pareil en version FILE* , sauf que là c'est en miniscule, stdout, stderr, et stdin
et printf c'est pas sale, printf fait un appel système à write de toutes façon
après peut être que tu veux dire qu'il faut mieux faire fprintf(stdout, .. pour pouvoir swapé plus facilement l'instruction en un message d'erreur, après dans ce cas autant utiliser un bon logger directement
parce que c'est pas code maison je dirais, moi-meme ca me fait mal au coeur de l'utiliser apres un mois de piscine a 42
Et alors? Est ce que tu ecrirais printf differement? Est ce que tu as ecris write ?
N'est ce pas la base du syndrome NIH? ( qui est certainement ce qu'il y a de pire dans le domaine)
Note en passant que write et printf ne font pas du tout la meme chose.
et printf c'est pas sale, printf fait un appel système à write de toutes façon
Note que ce n'est pas vrai ca! printf ne fait pas systematiquement un appel a write.
Le 09 août 2016 à 01:08:15 godrik a écrit :
et printf c'est pas sale, printf fait un appel système à write de toutes façon
Note que ce n'est pas vrai ca! printf ne fait pas systematiquement un appel a write.
ouais, c'est seulement quand il y a un \n où il flush c'est ça ?
Et alors? Est ce que tu ecrirais printf differement?
certainement moins bien
Est ce que tu as ecris write ?
bien sur que non, mais apres avoir passe du temps a ne travailler qu'avec les fonctions de base qui permettent pas grand chose a elles seules on s'y habitue et on prend gout a tout refaire (enfin refaire printf ca releve plus du calvaire), comme tu dis c'est la base du NIH
Le 09 août 2016 à 01:11:24 [DenshaOtoko] a écrit :
Le 09 août 2016 à 01:08:15 godrik a écrit :
et printf c'est pas sale, printf fait un appel système à write de toutes façon
Note que ce n'est pas vrai ca! printf ne fait pas systematiquement un appel a write.
ouais, c'est seulement quand il y a un \n où il flush c'est ça ?
Oula, c'est plus complique que ca en fait (j'ai ete lire posix et la gnulibc).
La gnulibc[1] dit qu'elle flush dans ces conditions la :
-When you try to do output and the output buffer is full.
-When the stream is closed. See Closing Streams.
-When the program terminates by calling exit. See Normal Termination.
-When a newline is written, if the stream is line buffered.
-Whenever an input operation on any stream actually reads data from its file.
En regardant posix[2] on se rend compte qu'il y a plein de comportement pas forcement attendu
A file may be subsequently reopened, by the same or another program execution, and its contents reclaimed or modified (if it can be repositioned at its start). If the main() function returns to its original caller, or if the exit() function is called, all open files are closed (hence all output streams are flushed) before program termination. Other paths to program termination, such as calling abort(), need not close all files properly.
Donc si tu prends sigterm, le buffer pars dans /dev/null
When a stream is "fully buffered", bytes are intended to be transmitted as a block when a buffer is filled. When a stream is "line buffered", bytes are intended to be transmitted as a block when a <newline> byte is encountered. Furthermore, bytes are intended to be transmitted as a block when a buffer is filled, when input is requested on an unbuffered stream, or when input is requested on a line-buffered stream that requires the transmission of bytes
Est ce que ca flush sur un newline depends de si le fd est "fully buffered" ou "lined buffered", trop lol hein Qu'en est il de stdout, stdin, et stderr.
At program start-up, three streams are predefined and need not be opened explicitly: standard input (for reading conventional input), standard output (for writing conventional output), and standard error (for writing diagnostic output). When opened, the standard error stream is not fully buffered; the standard input and standard output streams are fully buffered if and only if the stream can be determined not to refer to an interactive device.
Trop lol, stderr et stdout peuvent ne pas se comporter pareil
Et que dis le man posix de fopen:
When opened, a stream is fully buffered if and only if it can be determined not to refer to an interactive device.
Et naturellement un pipe c'est pas interactif. On voit ca super bien en executant ca:
erik@eriklaptop2:/tmp$ cat foo.c
#include <stdio.h>
#include <unistd.h>
int main () {
printf ("bla\n");
sleep(4);
printf ("bla\n");
}
erik@eriklaptop2:/tmp$ make foo
cc foo.c -o foo
erik@eriklaptop2:/tmp$ ./foo
bla
bla
erik@eriklaptop2:/tmp$ ./foo | cat
bla
bla
erik@eriklaptop2:/tmp$
ou le premier ./foo est line buffered, mais le deuxieme est fully buffered.
Note que je n'es pas vu dans posix (mais peut etre je l'ai loupe) la garantie que tout les output sont flushe quand il y a n'importe quel input.
Les interactions entre fd et stream et entre steam et fork/exec sont bien sympa aussi.
[1] http://www.gnu.org/software/libc/manual/html_node/Flushing-Buffers.html
[2] http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_05
Est ce que tu as ecris write ?
bien sur que non, mais apres avoir passe du temps a ne travailler qu'avec les fonctions de base qui permettent pas grand chose a elles seules on s'y habitue et on prend gout a tout refaire (enfin refaire printf ca releve plus du calvaire), comme tu dis c'est la base du NIH
Clairement ca a une valeure pedagogique de travailler a partir des fonctions exposer par le systeme. Il faut avoir ecrit malloc pour se rendre compte de l'horreur qui se passe en cas de buffer overflow/underflow.
Mais concretement un dev qui utilise write au lieu de printf ou fwrite, il cherche un peu a se faire taper. Principalement a cause des differences de buffering qui donne ce comportement wtf et inatendu, mais completement comprehensible une fois qu'on creuse:
erik@eriklaptop2:/tmp$ cat foo.c
#include <stdio.h>
#include <unistd.h>
int main () {
printf ("bla\n");
write (1, "foo\n", 4);
printf ("bla\n");
}
erik@eriklaptop2:/tmp$ make foo
cc foo.c -o foo
erik@eriklaptop2:/tmp$ ./foo
bla
foo
bla
erik@eriklaptop2:/tmp$ ./foo | cat
foo
bla
bla
erik@eriklaptop2:/tmp$
merci pour le résumé intéressant !
Godrik Je voulais remplacer le titre du topic par un write() car printf n'est pas approprié(semantiquement).
printf veut dire print formated et ça affiche une chaine de caractère formaté avec les paramètres passés, mais en l'occurence on passe aucun paramètre(printf('blabla')), et on se contente d'afficher une rvalue.
Printf -- qui n'est pas fait pour afficher betement des rvalue -- va passer "blabla" au moulin pour voir si il y a des paramètres à substituer dans la chaine, ceci coute en performance et dans certains cas, en sécurité aussi.
Si le premier paramètre de printf() est une valeur qu'un utilisateur peut modifier, alors le programme est vulnerable et peut être facilement exploité.
C'est vrai quoi
Appeler printf pour afficher une chaine de caractère qui n'est pas formaté n'a pas de sens
oui et non. Je ne suis pas completement convaincu par ton argument. En l'occurence, la chaine est statique et est donc controle par le developpeur. Ca a l'avantage compare a write ou a printf de ne pas avoir a specifier la taille de la chaine qui peut etre un probleme si c'est encode statiquement comme tu l'avais fait avecwrite (1, "blabla", 6);
Deja ca bypass le buffer de la libc, ce qui est souvent une mauvaise idee a moins que tout le code n'utilise pas al libc. Tu pourrais contourner les deux problemes avecfwrite (1, "blabla", strlen("blabla"));
mais c'est quand meme une bombe a retardement parceque tu pourrais changer l'un et oublier l'autre. Alors tu pourrais faireconst char * foo = "blabla";
fwrite (foo, strlen(foo), 1, 1);
mais ca fait une ligne de plus pour pas grand chose.
Mais en fait, c'est meme pire que ca parceque ni write ni fwrite ne garantissent que l'integralite du buffer ne sera ecrit. Donc en fait, le code correct est:{
size_t len;
const char * foo = "blabla";
while (len = strlen(foo))
foo += fwrite (foo, len, 1, 1);
}
Ce qui devient franchement casse couille a ecrire.
Et en plus, ca ne me parait pas clair que c'est beaucoup plus performant queprintf("blabla");
parce ca force a traverser la chaine au moins deux fois (et potentiellement plus si pour une raison bizarre, l'IO ne se fait pas en une fois.). Alors que l'appel a printf ne traversera la chaine qu'une seule fois et garantie que tout sera ecrit (sauf ferror). Apres je suis d'accord qu'il y a un petit overhead lie au decodage au cas ou il y aurait un format.printf ("%s", "blabla");
est certainement une meilleur option.
Donc non, utiliser write c'est juste une mauvaise idee.
Au pire on se casse pas la tête et on met Console.WriteLine("Blabla");
.
En incluant uniquement ce que j'utilise au lieu d'inclure les headers générique de Qt j'suis passé de plus de 2 minutes de compilation en debug à 1 minute, j'pensais pas que je gagnerais autant
lokilok, tu connais make -j ?
Non, c'est quoi ?
Ah ok je vois, c'est pour compiler plusieurs parties du programme en parallèle au lieu de les faire les unes à la suite des autres c'est ça ? J'vais voir l'essayer voir si ça diminue beaucoup ou pas (j'ai qu'un dual core).