Programm mit getc()

Gast #590093
Lesenswert?
• ▲
▼
Hi,
für ein Programm brauche ich die base64-Codierung. Ich habe mir mal das 
in der Wikipedia verlinkte Beispielprogramm 
http://base64.sourceforge.net/b64.c angesehen.

Dort gibt es folgenden Code (Ausschnitt):
1
while( !feof( infile ) ) {
2
    len = 0;
3
    for( i = 0; i < 3; i++ ) {
4
        in[i] = (unsigned char) getc( infile );
5
        if( !feof( infile ) ) {
6
            len++;
7
        }
8
        else {
9
            in[i] = 0;
10
        }
11
     }
12
.
13
.
Da die Abfrage auf EOF nur oben in der while-Bedingung stattfindet, kann 
getc() ja über EOF hinaus einlesen. Gibt es dann nicht einen Fehler?
Ist der Wert von EOF festgelegt, er fließt ja eigentlich laut diesem 
Beispiel mit in den codierten String ein.
Gast #590137
Lesenswert?
• ▲
▼
Laut manpage liefert getc() das nächste Zeichen, also wird der 
Filepointer erhöht.
Wird aber nun generell in getc() abgefragt ob der FP schon am Ende ist?

In stdio.h sieht es so aus
1
__CRT_INLINE int __cdecl getc (FILE* __F)
2
{
3
  return (--__F->_cnt >= 0)
4
    ?  (int) (unsigned char) *__F->_ptr++
5
    : _filbuf (__F);
6
}

Wenn ich noch wüsste, woher __F->_cnt stammt wär ich schlauer...
#590268
Lesenswert?
• ▲
▼
Thomas wrote:
> Hi,
> Dort gibt es folgenden Code (Ausschnitt):
>
1
> while( !feof( infile ) ) {
2
>     len = 0;
3
>     for( i = 0; i < 3; i++ ) {
4
>         in[i] = (unsigned char) getc( infile );
5
>         if( !feof( infile ) ) {
6
>             len++;
7
>         }
8
>         else {
9
>             in[i] = 0;
10
>         }
11
>      }
12
> .
13
> .
14
>
> Da die Abfrage auf EOF nur oben in der while-Bedingung stattfindet,

Nicht ganz.
Schau dir mal die Zeile nach dem getc() an.

Aber: In der Tat wird dieses immer wieder, selbst in Lehrbüchern,
falsch gemacht.
Die Funktione feof() ist nicht dazu gedacht, um damit die Schleife
zu steuern. Die korrekte Art und weise geht immer so:

   while( Zeichen konnte gelesen werden ) {
     verarbeite Zeichen;
   }

   if( eof ist nicht aufgetreten )
     Behandle Fehlerbedinung beim Lesen vom File
   else
     File wurde komplett gelesen, mach mit dem gelesenen weiter

C unterstützt dieses Schema dadurch, dass ausnahmslos alle
File Lese Funktionen einen Returnwert haben, der sich zur
Abfrage 'Zeichen konnte gelesen werden' eignet.

Im Falle von getc() liefert getc das Zeichen, bzw. EOF wenn
etwas schief gelaufen ist.

D.h. man zieht diese Schleife korrekter Weise so auf:
1
  int c;
2

3
  i = 0;
4

5
  while( ( c = getc( infile ) ) != EOF && i < 3 ) {
6
    in[i] = (unsigned char)c;
7
  }
8

9
  in[i] =  '\0';
10

11
  if( !feof( infile ) ) {
12
    // Behandle die Fehlerbedingung: einlesen vom File ging schief
13
  }
14
  else {
15
    // Behandle den Fall: die Daten wurden korrekt gelesen
16
  }

Der Unterschied zwischen der Methode hier und der original
Methode ist ganz einfach der, dass letztere Variante in
jedem Fall abbricht, wenn nicht korrekt vom File gelesen werden
konnte. In der ersten Methode kann es passieren, dass dies
ncith der Fall ist. Nämlich dann, wenn das File nicht bis zum
Ende gelesen wurde aber ein Fehler auftrat (Diskette fehlerhaft,
Kratzer in der CD, jemand hat das Laufwerk aufgemacht, Netzwerk-
verbindung ist abgebrochen, etc. Es gibt viele Gründe warum ein
Lesen von einem File schief gehen kann, nicht nur feof().
Persönliche Seite #590272
Lesenswert?
• ▲
▼
Karl Heinz, du musst i noch erhöhen nach jeder Iteration, ansonsten geht 
die Dauer der Schleife gegen Unendlich ;)

Btw, du (oder irgend jemand anderes) hattest das schonmal geschrieben. 
Ohne diese Information hätte ich es aber auch 100% falsch gemacht (bzw 
sogar falsch gelernt...).

Es wird nämlich tatsächlich in Lehrbüchern falsch gemacht...

Der "Trick" bei der Sache ist, dass getc() höchstens ein Zeichen(char) 
lesen kann, aber einen int zurückgibt. Dadurch ist noch etwas "Platz" um 
Fehler zu kennzeichnen, ohne dass das Zeichen zerstört werden würde.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren