Newsgroup: it.comp.lang.c++
Titolo: non ci capisco più niente!

Ho provato ad eseguire il seguente codice con il DJGPP, Borland C++ 5.02
ed il BCC 5.5:
#include <iostream.h>
#include <cstring>
int main()
{
  // -------- lettura di un numero ----------
  cout << "introduci un numero: ";
  int a = 0;
  cin >> a;
  cout << "a = " << a << '\n';
  // controllo
  cout << "in_avail = " << cin.rdbuf()->in_avail() << '\n';
  cout << "sync...\n";
  cin.sync();
  cout << "in_avail = " << cin.rdbuf()->in_avail() << '\n';
  cout << "fail: " << cin.fail() << '\n';
  // -------- lettura di un carattere ----------
  cout << "\nintroduci un carattere: ";
  char ch = 0;
  cin.get(ch);
  cout << "\nc = " << ch << '\t' << int(ch) << '\n';
  // controllo
  cout << "in_avail = " << cin.rdbuf()->in_avail() << '\n';
  cout << "sync...\n";
  cin.sync();
  cout << "in_avail = " << cin.rdbuf()->in_avail() << '\n';
  cout << "fail: " << cin.fail() << '\n';
  // -------- lettura di una C-string ----------
  cout << "\nintroduci una stringa: ";
  char p[10];
  cin.getline(p, 5, '\n');//, '\r');
  cout << "  s = " << p << '\n';
  // controllo
  cout << "fail: " << cin.fail() << '\n';
  cout << "in_avail = " << cin.rdbuf()->in_avail() << '\n';
  cout << "sync...\n";
  cin.sync();
  cout << "in_avail = " << cin.rdbuf()->in_avail() << '\n';
  cout << "fail: " << cin.fail() << '\n';
  // ------- resetta il buffer di lettura ---------
  const size_t BUFSIZE = 20;
  char temp[BUFSIZE];
  memset(temp, '\0', 20);
  cout << "\n\nreset the buffer...\n";
#ifdef STANDARD_CPP
  cin.rdbuf()->pubsetbuf(temp, BUFSIZE);
#else
  cin.rdbuf()->setbuf(temp, BUFSIZE);
#endif
  cout << "failed: " << cin.fail() << '\n';
  cout << "in_avail = " << cin.rdbuf()->in_avail() << '\n';
  cout << "cin.good(): " << cin.good() << '\n';
  int num;
  cout << "Introduci un numero:\n";
  cin >> num;
  cout << "  num = " << num << '\n';
  cout << "buffer: " << temp << '\n';
  cin.get();
  cin.get();
}
Tranne con il Borland C++ 5.02 (il quale perň non mi resetta il buffer) gli altri due
mi danno comportamenti assurdi!
Provate ad immettere come stringa un carattere od una decina....
Non so piů cosa pensare, o il mio codice non č legale, o mi sono fatto
una idea sbagliata della libreria di I/O del C++ oppure questi compilatori
hanno dei bug molto gravi.
Saluti  Manlio Perillo

   // ------- resetta il buffer di lettura ---------
Il resto pare non funzionare affatto. Mah...
EMG
PS. BCC55 e DJGPP.


Allora.
La prima cosa che non capisco è che quando ad esempio inserisco un numero all'inizio
mi trovo con in_avail() == 1. (Fin qui niente di strano)
Ma l'errore è che dopo faccio cin.sync() ma continuo ad ottenere in_avail() == 1.
Quindi non mi lascia inserire il carattere.
Seconda cosa: quando in getline inserisco solo 2 caratteri, quando premo invio l'input non
termina! Devo premere invio più volte.
Tutto questo con il BCC 5.5
Manlio Perillo

 termina! Devo premere invio più volte.
Perché hai messo due cin.get() alla fine. :-)
Ora vorrei tanto sapere la risposta al mio dubbio di cui sopra... :-)
EMG

 Perché hai messo due cin.get() alla fine. :-)
No, puoi anche togliere i due cin.get().
E' proprio getline() a dare questo strano problema.
Prova ad inserire, ad esempio "de".
Si deve premere due volte [INVIO] per uscire da getline().
Saluti  Manlio Perillo

 Si deve premere due volte [INVIO] per uscire da getline().
Sull'help del BCC55 c'è scritto
----------
istream_type& 
getline(char_type* s, streamsize n, char_type delim); 
Extracts characters and stores them into successive locations of an
array whose first element is designated by s. Characters are extracted
and stored until any of the following occurs:
n-1 characters are stored
	An end-of-file on the input sequence
	The next available input character == delim.
If the function stores no characters, it calls the basic_ios member
function setstate(failbit), which may throw ios_base::failure. In any
case, it stores a null character into the next successive location of
the array.
----------
da cui sembrerebbe che la getline() non termini se non incontra l'EOF.
EMG

 Lo Struostrup dice che sync() serve a fare il flush dell'input.
Al solito non ho sottomano i libri (sono via dall'Italia), ma la
pagina del Dinkum su <streambuf> dice:
The protected virtual member function endeavors to synchronize the
controlled streams with any associated external streams.  Typically,
this involves writing out any elements between the beginning and next
pointers for the output buffer. It does NOT involve putting back any
elements between the next and end pointers for the INPUT buffer. If
the function cannot succeed, it returns -1. The default behavior is to
return zero.
Per fare un esempio: ho finito poco fa, con l'aiuto determinante dei
guru di comp.lang.c++.moderated :-), di definire una classe stream
che, per ogni operazione di output tipo "stream << qualcosa", invia
identico output sia sullo schermo che su un file; li sync() viene
chiamato per assicurare, ad esempio, che ogni volta che un buffer
viene flushato la stessa cosa accada all'altro.
Incidentalmente, se lo stream e' bufferizzato ed il buffer interno
dello streambuf e' vuoto, i metodi chiamati per prendere un carattere
disponibile dallo stream sono underflow() e uflow().
-- 
Maurizio Loreti                         
http://www.pd.infn.it/~loreti/mlo.html
Univ. of Padova, Dept. of Physics - Padova, Italy            
lor...@pd.infn.it


Non so...
Quando premo [INVIO] mando il carattere '\n' e l'input dovrebbe terminare.
(almeno con il DJGPP ed il vecchio Borland C++ 5.02 č cosě)
Manlio Perillo

Interessante questa classe,
puo´ essere molto utile per un´analisi del comportamento di un programma.
Perche´ non la posti se e´ possibile?
grazie
Mauro


 Perche´ non la posti se e´ possibile?
E' un po' lunghetta da postare (ce ne sono anche due versioni; io
preferisco la seconda, "logout2").  La ho messa sul web, come
http://wwwcdf.pd.infn.it/MLO/logout.tar.gz
 ; se non hai il
decompressore (gzip) ed il dearchiviatore (tar) te la mando per mail.


 return zero.
Quindi non viene svuotato il buffer di input, ho capito bene?
EMG

 (almeno con il DJGPP ed il vecchio Borland C++ 5.02 è così)
No, neanche questo è corretto. L'input termina solo con l'end-of-file e
non con l'INVIO. Tanto è vero che l'INVIO stesso rimane disponibile nel
buffer di input per la successiva lettura.
EMG


A tale proposito, ancora non ho capito la differenza fra underflow() ed uflow()!
Lo Stroustrup dice che uflow() è usato nel caso in cui l'input è non bufferizzato;
ed infatti come esempio di snextc() scrive:
    if(gptr() == 0) return uflow();
    gbump(1);
    if(gptr() >= egptr()) return underflow();
    return *gptr();
Ma ciò non corrisponde a quello che dice lo standard (almeno l'ultimo draft)
ed a come è implementato nel BCC 5.5.
Spero che mi puoi charire questo dubbio.
Nota:  forse dovrei darle del lei e chiamarla professore, sono uno studente di Fisica
          all'Università di Salerno.
Grazie   Manlio Perillo

 Mi sembra che in C fflush svuoti il buffer di un file e stdin è un file.
Mi correggo.
Ho dato una occhiata al Kernighan ed è scritto che:
su di un input stream  fflush causa un effetto undefined.
Manlio Perillo

 Nota:  forse dovrei darle del lei
Qui ci sono solo membri della stesso club di appassionati; non credo
che conti nulla, in questo contesto, al di fuori della competenza (e,
ahime', ogni tanto mi capita di prendere delle cantonate colossali...)
Le sta bene, signor Perillo?                            8^)


 Le sta bene, signor Perillo?
Signor Perillo, credo proprio che prima o poi ci incontreremo visto che
studio informatica alla sua stessa università (magari per riprendere il
discorso sulle string!).
---Seek and Destroy---

 underflow() ed uflow()!
Entrambe le funzioni gestiscono il caso in cui il buffer e'
vuoto (o non esiste).  La differenza e' che uflow() avanza
la posizione corrente (consumando il carattere).
Entrambe le funzioni sono virtuali.
La versione base di underflow() si limita a restituire eof().
la versione base di uflow chiama underflow() e in caso di
successo avanza gptr():
  template <class Ch, class Tr>
  basic_streambuf<Ch, Tr>::int_type  basic_streambuf<Ch, Tr>::uflow()
  {
    if (traits_type::eq_int_type( underflow(), traits_type::eof() ))
      return traits_type::eof();
    else
      return traits_type::to_int_type( *gptr()++ );
  }
Per creare uno stream buffer bufferizzato basta ridefinire
underflow() e sfruttare la versione base di uflow().
Per creare uno stream buffer _non_ bufferizzato invece e'
necessario ridefinire anche uflow() perche' la versione base,
che muove gptr(), non va bene.
	Mauro


Su questo non sono d'accordo.
getline(buf, n)
legge fino a che non si introduce il carattere terminatore ('\n' per default)
Manlio Perillo


[...]
Grazie per la spiegazione esauriente.
Perň mi resta un dubbio.
Hai detto che si dovrebbe ridefinire uflow() per creare uno stream buffer _non_ bufferizzato.
Ma la libreria della Rogue Wave per filebuf non lo fa!
Eppure un file puň essere non bufferizzato.
Manlio Perillo


Che sorpresa!


Il fatto è che se tu fossi stato un mio professore proverei un certo
imbarazzo a darti del tu in questo newgroup per poi ridarti del lei
a lezione.
Tornando a cose più serie, ho letto il codice per logout;
trovo l'idea molto interessante.
Ho letto anche il tuo post su comp.lang.c++.moderated:
in effetti credo che derivare un nuovo streambuf sia una delle
cose più impegnative in C++.
Comunque se ci si appoggia ad uno streambuf 'concreto' (come nel
tuo caso) o se si deriva da uno streambuf 'concreto' - come filebuf -
(vedi ad esempio la mia risposta a Delusion's Master)
le cose sono notevolmente semplificate.
Attualmente mi sto cimentando nell'impresa di derivare uno streambuf
dallo streambuf di base (il che significa una diretta manipolazione del buffer).
Il mio scopo è di creare uno stream che usi le funzioni definite in conio
(fornite dalla Borland) getch() e putch() in modo da avere un input
che non debba attendere la pressione del testo [INVIO].
Ad esempio in.get() legge il carattere appena se ne preme uno.
Per avere delle idee su come procedere ho dato una occhiata all'ultimo
draft dello standard, ma in alcuni punti vengono dette cose (per me) sensa senso.
Fortuna che ho potuto dare una occhiata alla implementazione della libreria
del KAI C++ (la versione di prova mi è scaduta, ma il codice è rimasto).
Comunque sono semplificato nel mio compito in quanto l'input e
l'output sono separati (non come accade per filebuf in cui si può aprire
un file per lettura e scrittura).
Il programma l'ho praticamente finito ma mi sono dovuto fermare per un problema.
Uso il BCC 5.5 e giorni fa, appena finita la versione stabile, ho passato
mezza giornata a capire perchè si comportava in modo strano.
Fortuna che mi sono accorto che il problema era causato dalla libreria
della Rogue Wave (piena di bug).
Quindi sono in una situazione che non auguro a nessuno.
Ogni volta che ho un problema non so se è a causa della libreria od
a causa del mio codice...
Saluti  Manlio Perillo


Quello che intendevo non era svuotare il buffer di input;
il termine svuotare potrebbe trarre in inganno: svuotare dove?
Credo sia più corretto dire "clear buffer" (anche se lo Stroustup dice,
tra parentesi, "flush input").
Comunque adesso sono molto confuso.
Se, da quando ho capito, sync() svuota solo il buffer di scrittura,
PERCHE' istream ha una funzione membro
  int sync();
(che a sua volta chiama rdbuf()->pubsync())
MENTRE ostream ha una funzione membro
  ostream& flush();
(che a sua volta chiama rdbuf()->pubsync())
???
Manlio Perillo

 legge fino a che non si introduce il carattere terminatore ('\n' per default)
Ma è la funzione che prevede un carattere di terminazione. Il problema è
che finché ci sono caratteri nello stream una chiamata successiva (se la
funzione non se li mangia) continuerà leggendoli.
EMG

 Eppure un file puň essere non bufferizzato.
Non conosco la libreria Rogue Wave, quindi posso solo
fare delle ipotesi.
Probabilmente filebuf usa il buffer anche nella modalita'
non bufferizzata, ma lo riempe con un solo carattere alla volta.
Esempio (senza controllo di errori/eof):
  class filebuf {
    ...
    char_type ch;
    bool unbuffered;
 
    streambuf setbuf( char_type* s, streamsize n )
    {
      if (s == 0  &&  n == 0)
        unbuffered = true;
    }
 
    int_type underflow()
    {
      if (unbuffered) {
        ch = read_one_char_from_file();
        setg( &ch, &ch, &ch+1 );
        return ch;
      }
        ...
    }
    ....
  };
In questo caso streambuf::uflow() va bene.
La ridefinizione di uflow() e' necessaria quando lo stream buffer
e' veramente non bufferizzato, cioe'  eback == gptr == egptr == 0,
e non si puo' consumare un carattere incrementando gptr.
	Mauro

 ???
Giŕ, se basic_streambuf::sync() veramente non facesse niente allora come
fa ostream a svuotare il buffer? Mah...
EMG

 wrote in message 399D7654...@flashnet.it...
[...]
Forse ci stiamo fraintendendo a vicenda.
Riscrivo il codice 'incriminato':
#include <iostream.h>
#include <cstring.h>
int main()
{
   const size_t SIZE = 10;
   char buf[SIZE];
   cout << "introduci una stringa:  ";
   cin.getline(buf, SIZE);
   cout << "buf = " << buf;
   cout << "     di lunghezza: " << strlen(buf) << '\n';
   cout << "in_avail: " << cin.rdbuf()->in_avail() << '\n';
   cout << "failed: " << cin.fail() << '\n';
}
Se voglio introdurre la stringa "123" con il BCC 5.5 devo scrivere:      [1][2][3][INVIO][INVIO]
-- BUG! --
Se voglio introdurre "123456789" devo fare  [1][2][3][4][5][6][7][8][9][INVIO]
-- OK! --
Se introduco "123456789012" devo premere invio una sola volta ma ottengo cin.fail() == true
-- BUG? ---
(anche con il DJGPP cin fallisce)
Manlio Perillo


Chiarissimo,  grazie.
Manlio Perillo


Ma allora perchč nella classe istream č presente il metodo sync()??
Se in pratica modifica solo l'output, che senso ha metterlo in una classe per l'input?
E' a causa di questo punto se sono cosě confuso!
Manlio Perillo

 Riscrivo il codice 'incriminato':
Si, avevo capito. E non so rispondere... :-(
EMG

 wrote in message 399D4FB7...@iperbole.bologna.it...
[...]
Ancora un dubbio (sapessi quanti ne ho... peccato che non esista un libro con la spiegazione di tutto)
Se gptr() == 0, questo non vuol dire che l'input non č bufferizzato, vero?
Ad esempio la libreria del KAI C++ setta  setg(0, 0, 0) per marcare la get area
come inusabile, a meno che non si chiami underflow().
Grazie   Manlio Perillo

 la get area come inusabile, a meno che non si chiami underflow().
Uno stream buffer non bufferizzato tiene sempre gtpr == pptr == 0.
Uno bufferizzato puo' avere a volte g/pptr == 0 quando la get/put
area e' temporaneamente inattiva, come ad esempio prima della 
prima chiamata a under/overflow().
Alcuni stream buffer usano lo stesso buffer interno sia per l'input
che per l'output e quando la put area e' attiva, la get area deve
ovviamente essere inattiva (gptr == 0).
	Mauro

Tenete presente che "flush" e' il verbo che indica l'attivita' dello
sciacquone...
Ciao,
Nicola