1

Je viens de passer 1 heure à chercher ce qui pouvait bien faire boguer mon programme... Et je viens de comprendre que le bug ne vient pas de mon code mais d'un étrange comportement de printf doom


Compilez ceci avec GCC :
#include <time.h>
#include <stdio.h>


int main(int argc, char *argv[]) {
    time_t  now=  0;
    time_t  last= 0;
    
    while (1) {
        now= time(NULL);
        if (now != last) {
            last= now;
            printf("1 SECONDE...\n");
        }
    }
    
    return (0);
}
Comme on s'y attend, 1 SECONDE s'affiche une fois par seconde.


Maintenant, compilez ceci (la seule différence avec le code d'au-dessus, c'est qu'il n'y a pas de \n à la fin du printf) :
#include <time.h>
#include <stdio.h>


int main(int argc, char *argv[]) {
    time_t  now=  0;
    time_t  last= 0;
    
    while (1) {
        now= time(NULL);
        if (now != last) {
            last= now;
            printf("1 SECONDE... ");
        }
    }
    
    return (0);
}
Plus rien ne s'affiche confus
avatar
Un site complet sur lequel vous trouverez des programmes et des jeux pour votre calculatrice TI 89 / Titanium / 92+ / Voyage 200 : www.ti-fr.com.
Quelques idées personnelles ici.

2

Je suis sur Kubuntu 9.04 64 bits.
avatar
Un site complet sur lequel vous trouverez des programmes et des jeux pour votre calculatrice TI 89 / Titanium / 92+ / Voyage 200 : www.ti-fr.com.
Quelques idées personnelles ici.

3

a priori c'est tout à fait normal : le \n provoque automatiquement le flush du buffer (et donc l'affichage à l'écran), tu dois avoir une fonction pour flusher manuellement si ce que tu affiches ne contient pas de \n.

[edit] fflush on dirait, à confirmer
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

4

Confirmé.
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

5

OK, mais j'estime que ce n'est pas normal. On demande un affichage, il ne se fait pas.
J'essaie votre astuce demain. Merci !
avatar
Un site complet sur lequel vous trouverez des programmes et des jeux pour votre calculatrice TI 89 / Titanium / 92+ / Voyage 200 : www.ti-fr.com.
Quelques idées personnelles ici.

6

C'est indiqué dans la doc quelque part, mais c'est vrai que ce n'est pas intuitif (et ça le fait sous Linux, mais pas sous Windows).
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

7

Thibaut (./5) :
OK, mais j'estime que ce n'est pas normal. On demande un affichage, il ne se fait pas.

Bah si c'est normal, la fonction est prévue pour fonctionner comme ça, c'est son comportement prévu et documenté. Si tu veux une écriture immédiate, tu peux par exemple utiliser write (quitte à recoder ton propre printf par-dessus).

C'est pas parceque la libc ne fonctionne pas exactement comme tu t'y attends qu'elle est forcément illogique ou mal conçue hein ^^
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

8

printf est buffurisé, meme sous windows, j'ai deja eu des "pertes" d'affichage a cause de ça, mais je confirme, il faut utiliser fflush(stdout) pour etre que ça sera afficher. Mais les perfs en prennent un sacré cout...
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

9

Perso je l'ai jamais observé sous Windows et Zephyr non plus (on en discutait sur IRC), mais ça se peut.
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

10

Ce n'est pas aussi flagrant que sous linux, c'est certain, je faisait du multithread & autres trucs du genre quand ça m'est arrivé avec pas mal de donnée sur la console (Et ça date, c'était sous NT4 pendant mon BTS)
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

11

Bah, ce n'est pas une petite calculatrice où tout est simple et immédiat, sur un PC, il y a beaucoup d'optimisations de performance complexes qui peuvent parfois causer ce genre de comportements inattendus.
avatar
Mes news pour calculatrices TI: Ti-Gen
Mes projets PC pour calculatrices TI: TIGCC, CalcForge (CalcForgeLP, Emu-TIGCC)
Mes chans IRC: #tigcc et #inspired sur irc.freequest.net (UTF-8)

Liberté, Égalité, Fraternité

12

Sauf que linux ne flush JAMAIS tant qu'on a pas fait un fflush ou un \n (et ce n'est pas printf qui est en cause, mais la console en elle meme, ça touche aussi les printk par exemple)
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

13

Ah, tiens tiens ! Je savais que std::endl flushait alors que \n non en C++, mais j'ignorais que ça avait ce comportement en C !

14

Bon, on est quelques uns à apprendre un truc. J'ai regardé le man de printf, et ce comportement n'y est pas. Il me semblait bien n'en avoir jamais entendu parler. C'est logique que ce soit bufferisé en fait, mais le flush devrait être automatique (10 fois par seconde par exemple).

L'explication que vous avez donnée eclaircit d'autres bugs graphiques qui n'avaient rien à voir à première vue. Je comprends enfin pourquoi le curseur scintille très vite le long de la ligne lorsque je réécris plusieurs fois par seconde sur la même ligne (grace à \r).
avatar
Un site complet sur lequel vous trouverez des programmes et des jeux pour votre calculatrice TI 89 / Titanium / 92+ / Voyage 200 : www.ti-fr.com.
Quelques idées personnelles ici.

15

Pour la console linux, il me *semble* qu'il y a une commande (genre ANSI) permettant de stopper le buffering a verifier (mais je suis tellement HS ce matin, et ça promet pour la journée, que zzz pour chercher)
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

16

Thibaut (./14) :
J'ai regardé le man de printf, et ce comportement n'y est pas.


Normal ça n'a rien à voir avec printf mais avec les tty, ou bien avec la libc, j'hésite.
Je pense que fputs, fputc et fwrite on le même comportement.

bon ben vala, voir man 3 setbuf pour choisir entre unbuffered, line buffered (par défaut) et block buffered.

Il n'y a donc aucune raison que le flush soit automatique , cela demanderait un thread particulier ou un timer ou un jenesékoi.

c'est en plus apparemment conforme à C89 et C99, donc inutile de cracher sur qui que ce soit.

c'est fucking normal, rien de plus.

17

Ce n'est apriori pas la libc, mais bien le tty, vu que printk (qui n'a rien a voir avec la libc) est touché par le soucis smile

Et attention, stdout est "touché" mais stdin, et stderr le sont aussi !
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

18

Merci des précisions squalyl, mais on est bien d'accord que ce comportement n'est pas justifiable par celui de fprintf, fputs et compagnie. Il s'agit d'affichage, d'une interaction avec l'utilisateur mal réalisée, d'autant plus problématique qu'elle est mal documentée.
avatar
Un site complet sur lequel vous trouverez des programmes et des jeux pour votre calculatrice TI 89 / Titanium / 92+ / Voyage 200 : www.ti-fr.com.
Quelques idées personnelles ici.

19

#linux# #modcoquin# ?

20

désolé mais je vais arrêter là les discussions, car je trouve ce comportement très logique, ça s'appelle la mise en cache et si tu la veux pas on te donne l'api pour la désactiver.

ce que tu veux n'est pas standard, flemme d'expliquer pourquoi a base d'arguments historiques sur les TTY et/ou les performances.


je vois pour info
man setbuf a dit:
Normally, all files are block buffered. When the first I/O operation
occurs on a file, malloc(3) is called and an optimally-sized buffer is
obtained. If a stream refers to a terminal (as stdout normally does), it
is line buffered. The standard error stream stderr is always unbuffered.
mais il faut savoir ou chercher.

faut pas abuser, c'est quand même simple ,
soit tu fais printf("blabla\n")
soit tu fais printf(blabla) plus fflush(stdout)
soit tu fais setvbuf(stdout, NULL, _IONBF, 0); avant le reste

et si tu veux toujours pas céder ou pas réécrire ton code tu fais un LD_PRELOAD

#include <dlfcn.h>
#include <stdio.h>
#include <stdarg.h>
static void * libc=NULL;
typedef int (*vprintf_t)(const char *, va_list);
static vprintf_t oldvprintf=NULL;
int printf(const char *fmt, ...) {
    va_list ap;
    int retval;
    va_start(fmt,ap);
    if(libc==NULL) libc=dlopen("/lib/libc.so.6",RTLD_LAZY);
    if(libc==NULL) exit(1);
    oldvprintf=dlsym(libc, "vprintf");
    if(oldvprintf==null) exit(1);
    retval=oldvprintf(fmt, ap);
    va_end(ap);
    fflush(stdout);
    return retval;
}
(écrit à la main, a arranger sans doute)
intf(fmt, ap); va_end(ap); return retval; }
ou encore (même pas la peine de faire du dlmachin) #include <stdio.h>
#include <stdarg.h>
static int firstcall=1;
int printf(const char *fmt, ...)
{
    va_list ap;
    int retval;
    va_start(fmt,ap);
    if(!firstcall)
    {
        setvbuf(stdout,NULL,_IONBF,0);
        firstcall=0;
    }
    retval=vpr
tval; }
ou même#include <stdio.h>
#include <stdarg.h>
int printf(const char *fmt, ...)
{
    va_list ap;
    int retval;
    va_start(fmt,ap);
    retval=vprintf(fmt, ap);
    va_end(ap);
    fflush(stdout);
    return re
(écrit à la main, a arranger sans doute)

gcc -shared -fPIC flushprintf.c -o flusprintf.so
LD_PRELOAD=./flushprintf.so ./mefepluchier

si tu veux que ça reste tu peux en faire une variable d'env dans ton .bashrc

21

Thibaut t'es ridicule, ça fait des années que printf fonctionne comme ça et la terre continue de tourner, c'est pas parceque t'as perdu 2h sur ce problème qu'il faut prétexter que c'est parceque c'est mal conçu grin

(je suis d'accord que c'est chiant de se faire avoir quand on est pas au courant, mais c'est pas non plus la peine de passer 2 pages à prétendre que les lib système sont mal codées)
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

22

Et ce n'est pas fait pour rien, si tu a une console un peu lente (genre une liaison série a 115200 par exemple) des printf non bufferisé (et meme avec d'ailleurs, mais de maniere moindre) font ralentir un programme d'une maniere concidérable (on peut attendre un facteur 100 si le volume d'affichage est enorme)
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

23

Hey je dis que c'est mal conçu sur PC et que c'est surtout anormal que ce soit pas dit dans la doc de la fonction. Jusqu'à preuve du contraire, il n'y a pas de buffering sur les interfaces graphiques, toute écriture apparaît en moins d'un dixième de seconde. Un programmeur peut légitimement attendre la même chose sur une console PC quand la doc officielle ne dit rien. Windows semble mieux conçu sur ce point. Oui vos standards sont géniaux mais faut avertir des conséquences quand ils sont mal adaptés sur un système (ce qui me fait rire c'est celui qui évoque des raisons historiques).
avatar
Un site complet sur lequel vous trouverez des programmes et des jeux pour votre calculatrice TI 89 / Titanium / 92+ / Voyage 200 : www.ti-fr.com.
Quelques idées personnelles ici.

24

zzz
c'est pas graphique, ça doit être compatible avec TOUTES les consoles y compris par port série, communication spatiale à 240 bits seconde, etc
zzz
c'est pas a cause de cette fonction
zzz
c'est écrit dans la doc de la fonction responsable
zzz
troll winux trop gros passera pas la porte du #mac#
zzz

25

Excuse-moi mais tu as écrit plus haut que c'est la console qui avait ce comportement. Eh bien il est inutile et gênant sur l'écran d'un PC : le programme veut montrer quelque chose à l'utilisateur, la console ne le montre pas !
On s'en fout de la faute à qui c'est. C'est un genre de raisonnement qui m'échappe. printf ne fonctionne pas comme on s'y attend alors cela doit être signalé dans la doc (avec AU MINIMUM un "voir aussi : fflush" à la fin).
Prends le comme un troll mais on ne fait pas évoluer les choses si on part toujours du principe qu'elles sont parfaites.

Bref, je vais appeler fflush après chaque printf.
avatar
Un site complet sur lequel vous trouverez des programmes et des jeux pour votre calculatrice TI 89 / Titanium / 92+ / Voyage 200 : www.ti-fr.com.
Quelques idées personnelles ici.

26

Thibaut (./26) :
printf ne fonctionne pas comme on s'y attend


le problème est là. Comme TU l'attends.

il y sans doute autant de manières de comprendre printf() que de gens. il a bien fallu en choisir une, tout en tenant compte de raisonnements techniques, car il s'agit d'une API qui ne sert pas qu'à parler à un utilisateur.

il y a des quantités de trucs de ce genre. je suis vraiment en pétard contre linux car les appels à socket() ne sont pas non-bloquant par défaut. Quelle honte! C'est pas ce que j'attendais. J'en ai besoin, merde, ça fait chier de devoir appeler setsockopt(O_NONBLOCK) à chaque fois. Mais c'est comme ça.

mais bon, je vois que tu a pris la bonne méthode: fflush().

vala. la vie est vraiment trop inzuste sad

(quant au mauvais man, tu sais très bien que la libc est open source, effectivement c'est donc trivial, tu n'as qu'à proposer un patch au mainteneur de la libc, il ajoutera sans aucune difficulté ton commentaire concernant le seealso->fflush ou une NOTE à la fin de la page, en plus on verra ton nom dans les crédits)

(mon ton est volontairement ironique, les docs mal faites c'est ni la première fois ni la dernière)

27

Petit test simple :
gdz@confucius ~/tmp $ ls test*.c
test1.c  test2.c  test3.c
gdz@confucius ~/tmp $ cat test*.c
/* test1.c */
#include <stdio.h>


int main(int argc, char *argv[])
{
   unsigned long i, j;
   for(i = 0; i < 65535; i++)
   {	
      printf(".");
   }
}
/*
 * vim: textwidth=79 ts=3 sts=3 expandtab
 */
/* test2.c */
#include <stdio.h>


int main(int argc, char *argv[])
{
   unsigned long i, j;
   for(i = 0; i < 65535; i++)
   {	
      printf(".");
      fflush(stdout);
   }
}
/*
 * vim: textwidth=79 ts=3 sts=3 expandtab
 */
 /* test3.c */
#include <stdio.h>


int main(int argc, char *argv[])
{
   unsigned long i, j;
   for(i = 0; i < 65535; i++)
   {	
      //printf(".");
   }
}
/*
 * vim: textwidth=79 ts=3 sts=3 expandtab
 */
gdz@confucius ~/tmp $ gcc test1.c -o test1
gdz@confucius ~/tmp $ gcc test2.c -o test2
gdz@confucius ~/tmp $ gcc test3.c -o test3
gdz@confucius ~/tmp $ time ./test1
...... [snap] ....
real	0m0.537s
user	0m0.008s
sys	0m0.000s
gdz@confucius ~/tmp $ time ./test2
...... [snap] ....
real	0m0.670s
user	0m0.012s
sys	0m0.104s
yep@confucius ~/tmp $ time ./test3

real	0m0.003s
user	0m0.000s
sys	0m0.000s

Le volume a afficher n'est pas enorme dans ce cas, et la console flush automatiquement quand le buffer dépasse une certaine taille, en plus du moment ou il rencontre un "\n", mais la différence de temps d'execution est plus que notable
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

28

squalyl : L'ironie est peut-être inappropriée. En dehors de mon avis, Zerosquare considère qu'on est dans un cas contre-intuitif et Godzil a parlé de "souci". En fait, n'importe qui de normalement constitué doit s'attendre à voir "bonjour" affiché quand il écrit printf("bonjour"). La doc est mal faite, on se rejoint bien sur là dessus.

Pas de problème pour ajouter cette information importante. Mais comment savoir à qui s'adresser ?
avatar
Un site complet sur lequel vous trouverez des programmes et des jeux pour votre calculatrice TI 89 / Titanium / 92+ / Voyage 200 : www.ti-fr.com.
Quelques idées personnelles ici.

29

"libc" "maintener". Ou au pire, il doit bien y avoir des contacts sur le site de la fsf

30

Godzil : Petit test sympa smile Ca montre l'apport du buffering sur un cas extrême, et on s'y attend. Si tu prends un cas plus concret, par exemple afficher 65535 fois "abcdef", l'écart se resserre ?
avatar
Un site complet sur lequel vous trouverez des programmes et des jeux pour votre calculatrice TI 89 / Titanium / 92+ / Voyage 200 : www.ti-fr.com.
Quelques idées personnelles ici.