Forum: Compiler & IDEs Programm mit getc()


von Thomas (Gast)


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.

von Florian (Gast)


Lesenswert?

Der Quelltext ist in der Tat unschön.
1
      if( !feof( infile ) ) {
2
            len++;
3
        }
4
        else {
5
            in[i] = 0;
6
        }

Hier wird bei EOF eine 0 abgespeichert.

von Thomas (Gast)


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...

von Karl H. (kbuchegg)


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().

von Simon K. (simon) Benutzerseite


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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.