Ich muss eine Textzeile lesen (mit einem Zeilenende versehen), ohne Annahmen über die Länge zu machen. So sehe ich jetzt Möglichkeiten:
fgets
und prüfen Sie jedes Mal, ob das letzte Zeichen ein Zeilenumbruch ist und kontinuierlich an einen Puffer angehängt wird fgetc
und gelegentlich mit realloc
dem Puffer Intuition sagt mir, dass die fgetc
Variante möglicherweise langsamer ist, aber dann sehe ich nicht, wie fgets
es tun kann, ohne jedes Zeichen zu prüfen (auch meine Intuition ist nicht immer so gut). Die Linien sind ziemlich groß, deshalb ist die Leistung wichtig.
Ich würde gerne die Vor- und Nachteile jedes Ansatzes kennen. Vielen Dank im Voraus.
Ich schlage vor, fgets()
in Verbindung mit dynamischer Speicherzuweisung zu verwenden - oder Sie können die Schnittstelle zu % co_de untersuchen % im POSIX 2008-Standard und auf neueren Linux-Rechnern verfügbar. Das macht die Speicherzuweisung für Sie. Sie müssen sowohl die Pufferlänge als auch die Adresse im Auge behalten, damit Sie sich selbst eine Struktur für die Verarbeitung der Informationen erstellen können.
Obwohl getline()
auch funktioniert, ist es marginal fiddlier - aber nur marginal so. Unter den Deckeln verwendet es dieselben Mechanismen wie fgetc()
. Die Interna können möglicherweise eine schnellere Operation ausnutzen - analog zu fgets()
-, die nicht verfügbar sind, wenn Sie strchr()
direkt aufrufen.
Bietet Ihre Umgebung die Funktion getline(3)
? Wenn ja, würde ich sagen, gehen Sie dafür.
Der große Vorteil, den ich sehe, ist, dass er den Puffer selbst zuweist (wenn Sie wollen) und realloc()
den Puffer, den Sie übergeben, wenn er zu klein ist. (Das bedeutet, dass Sie etwas, das von malloc()
erhalten wurde, weitergeben müssen).
Dies beseitigt einige der Schmerzen von fgets / fgetc, und Sie können hoffen, dass derjenige, der die C-Bibliothek geschrieben hat, die es implementiert, darauf achtete, es effizient zu machen.
Bonus: Die Manpage unter Linux hat ein schönes Beispiel dafür, wie man es effizient einsetzen kann.
Wenn Ihnen die Leistung wichtig ist, möchten Sie in der Regel getc
anstelle von fgetc
aufrufen. Der Standard versucht, getc
als Makro zu implementieren, um den Funktionsaufruf zu vermeiden.
Früher war die Hauptsache wahrscheinlich Ihre Strategie bei der Zuweisung des Puffers. Die meisten Leute verwenden feste Inkremente (z. B. wenn / wenn der Speicherplatz knapp wird, weitere 128 Bytes zuweisen). Ich rate stattdessen, einen konstanten Faktor zu verwenden. Wenn Ihnen der Speicherplatz ausgeht, weisen Sie einen Puffer zu, der etwa 1 1/2 mal so groß ist wie die vorherige Größe.
Besonders wenn getc
als Makro implementiert ist, ist der Unterschied zwischen getc
und fgets
normalerweise sehr gering, so dass Sie sich besser auf andere Probleme konzentrieren sollten.
Wenn Sie eine maximale Zeilenlänge festlegen können, sogar eine große, dann würde ein fgets
den Trick machen. Wenn nicht, sind mehrere fgets
-Aufrufe immer noch schneller als mehrere fgetc
-Aufrufe, da der Overhead der letzteren höher ist.
Eine bessere Antwort ist jedoch, dass es sich nicht lohnt, sich über den Leistungsunterschied Gedanken zu machen, solange und solange Sie nicht müssen. Wenn fgetc
schnell genug ist, was ist es dann wichtig?
Ich würde einen großen Puffer zuweisen und dann fgets verwenden, überprüfen, neu zuweisen und wiederholen, wenn Sie nicht bis zum Ende der Zeile gelesen haben.
Jedes Mal, wenn Sie lesen (entweder über fgetc oder fgets), führen Sie einen Systemaufruf aus, der Zeit benötigt. Sie möchten die Häufigkeit des Auftretens minimieren. Das heißt, dass fgets weniger oft aufgerufen werden und das Iterieren im Speicher schneller ist.
Wenn Sie von einer Datei lesen, ist mmap()
ing in der Datei eine andere Option.