Wie verwende ich fgets (), um zu vermeiden, dass das zweite Argument vom Typ int umgewandelt wird?

8

Die Deklaration der Funktion fgets sieht folgendermaßen aus:

%Vor%

Dies bedeutet, dass das zweite Argument voraussichtlich ein int ist.

Was ist der richtige Weg, um dieses Casting im folgenden Programm zu vermeiden?

%Vor%

Hier habe ich (int)len verwendet, was gut aussieht, aber was passiert, wenn buffer eine sehr lange Zeichenfolge speichert?

Sagen wir:

%Vor%

Ich habe bereits die Länge des Typs size_t angegeben, was hier in Ordnung ist, aber wenn ich sie an% co_de weitergeben werde, ist% nicht OK wegen:

%Vor%

und wenn ich es auf fgets umsetze passt nicht, weil die Größe von int kleiner ist als die Größe von int und einige Informationen verloren gehen.

Vielleicht fehlt mir hier etwas ...

Wie kann ich diese Situation vermeiden?

    
Michi 18.07.2016, 10:39
quelle

4 Antworten

5
%Vor%

Mit fgets() kann der Eingabepuffer s[INT_MAX] und darüber hinaus nicht verwendet werden.

Der size_t len -Code von OP könnte die int -Cast von len vermeiden, indem er in eine Zeichenkette konvertiert und wieder in eine int konvertiert, was einfach verschwenderisch ist. Eine Besetzung ist das Richtige.

Anstatt Code mit (int) zu streichen, reduzieren / kontrollieren Sie dessen Verwendung und fassen Sie den Cast in eine einschränkende Hilfsfunktion.

%Vor%

Wenn der Code wirklich lange Zeilen lesen muss, berücksichtigen Sie ssize_t getline(char **lineptr, size_t *n, FILE *stream); wie definiert hier . Beachten Sie, dass dies eine nicht standardmäßige C-Bibliotheksfunktion ist, deren Quellcode jedoch leicht verfügbar ist.

Bezüglich der pedantischen Verwendung von fgets() gibt es mindestens 2 Gründe dafür, dass fgets() NULL zurückgibt: Dateiende- und Eingabefehler. Betrachten Sie nun den Eckfall mit dem OP-Code

%Vor%

und pathologische Fälle wie

%Vor%

Beide werden unter diskutiert. Gibt fgets () NULL mit einem kurzen Buffer-kompatiblen Befehl zurück?

    
chux 18.07.2016, 13:14
quelle
2

Wenn Sie das Problem des Integer-Überlaufs vermeiden möchten, können Sie eine Wertüberprüfung durchführen und entsprechend handeln. Beachten Sie, dass, da strlen() den Wert vom Typ size_t zurückgibt, Sie 2 Optionen haben. Deklarieren Sie entweder eine Variable vom Typ int und weisen Sie ihr den Rückgabewert strlen() zu, der eine implizite Konvertierung vom Typ size_t nach int durchführt oder wie in Ihrem Funktionsaufruf umgesetzt wird.

Hier ist eine mögliche Lösung:

%Vor%     
user6274708 18.07.2016 11:06
quelle
1

Ich würde nicht die Dimension des Arguments mit fgets() mit der Dimension von buffer verknüpfen.

Stattdessen würde ich sicherstellen, dass der zum Lesen verwendete Puffer eine Länge hat, die mit int dargestellt werden kann (dh INT_MAX nicht überschreitet). Wenn Sie wirklich portabel sein möchten, stellen Sie sicher, dass die Pufferlänge 32767 nicht überschreitet (der Standard gibt an, dass der minimal zulässige Wert von INT_MAX 32767 ist).

Dann nutzen Sie die Tatsache, dass fgets() eine Zeile in Teilen liest, wenn die Zeilenlänge die Pufferlänge überschreitet.

Angenommen, len überschreitet die Länge einer Zeile, die von stdin gelesen wird;

%Vor%

Beachten Sie, dass, wenn dem Dateiende nicht unmittelbar ein '\n' vorangestellt wird, der obige Text den Text nach dem letzten '\n' verwirft.

Im obigen Fall ist der Ersatz von fgets(read_buffer, 10, stdin) durch fgets(read_buffer, sizeof read_buffer, stdin) sicher, da ein size_t mit einem Wert kleiner oder gleich INT_MAX immer sicher in int konvertiert werden kann. Wenn Sie also einen Compiler von der Ausgabe von Warnungen abhalten möchten, können Sie sicher casten, d. H.% Co_de%

    
Peter 18.07.2016 11:43
quelle
0

Entwurf sagt, dass

  

Das Ergebnis der Umwandlung einer Ganzzahl in eine kürzere Ganzzahl mit Vorzeichen oder   das Ergebnis der Umwandlung einer vorzeichenlosen Ganzzahl in eine vorzeichenbehaftete Ganzzahl von   gleiche Länge, wenn der Wert nicht dargestellt werden kann

ist implementierungsdefiniert. Als Ergebnis, wenn Sie den Wert eines vorzeichenlosen Typs sicher in ein Vorzeichen konvertieren möchten, müssen Sie sicherstellen, dass alle möglichen Quellwerte mit dem Zieltyp signed dargestellt werden können.

    
Sergio 18.07.2016 11:14
quelle

Tags und Links