Frage

In neuem C ++ Code, neige ich dazu, die C ++ iostream-Bibliothek zu verwenden, anstatt der C stdio Bibliothek.

Ich habe bemerkt, scheinen einige Programmierer stdio zu halten und bestand darauf, dass es mehr tragbar.

Ist das wirklich der Fall? Was ist besser zu nutzen?

War es hilfreich?

Lösung

die ursprüngliche Frage zu beantworten:
Alles, was mit stdio getan werden kann kann mit der iostream-Bibliothek erfolgen.

Disadvantages of iostreams: verbose
Advantages    of iostreams: easy to extend for new non POD types.

Der Schritt der C ++ gemacht über C war Typsicherheit.

  • iostreams wurde entwickelt, explizit wird sicher ein. Somit Zuordnung zu einem Objekt überprüft explizit den Typ (bei Compilers Zeit) des Objekts zu zugewiesen wird (eine Kompilierung Fehler zu erzeugen, wenn erforderlich). So Laufzeitspeicher Überläufe verhindern oder einen Float-Wert auf ein char-Objekt zu schreiben usw.

  • scanf () / printf () und Familie auf der anderen Seite verläßt sich auf den Programmierern das Format richtig bekommen und es gab keine Typprüfung (ich glaube, gcc eine Erweiterung, die hilft). Als Ergebnis war es die Quelle vieler Fehler (als Programmierer sind weniger perfekt in ihrer Analyse als Compiler [nicht Compiler perfekt gehen zu sagen, einfach besser als Menschen]).

Nur um zu klären Kommentare von Colin Jensen.

  • Die iostream-Bibliotheken wurden stabil seit der Veröffentlichung des letzten Standard (ich das aktuelle Jahr vergessen, aber vor etwa 10 Jahren).

Zur Klärung Kommentare von Mikael Jansson.

  • Die anderen Sprachen, die er, der das Format Stil haben explizite Garantien verwenden erwähnt die gefährlichen Nebenwirkungen der C stdio Bibliothek zu verhindern, die (in C, aber nicht die genannten Sprachen) kann eine Laufzeit Absturz führen.

NB. Ich bin damit einverstanden, dass die iostream-Bibliothek ein bisschen auf der ausführlichen Seite. Aber ich bin bereit, mit dem verboseness zu setzen, um Laufzeitsicherheit zu gewährleisten. Aber wir können die Ausführlichkeit mildern von Format Bibliothek Erhöhung .

#include <iostream>
#include <iomanip>
#include <boost/format.hpp>

struct X
{  // this structure reverse engineered from
   // example provided by 'Mikael Jansson' in order to make this a running example

    char*       name;
    double      mean;
    int         sample_count;
};
int main()
{
    X   stats[] = {{"Plop",5.6,2}};

    // nonsense output, just to exemplify

    // stdio version
    fprintf(stderr, "at %p/%s: mean value %.3f of %4d samples\n",
            stats, stats->name, stats->mean, stats->sample_count);

    // iostream
    std::cerr << "at " << (void*)stats << "/" << stats->name
              << ": mean value " << std::fixed << std::setprecision(3) << stats->mean
              << " of " << std::setw(4) << std::setfill(' ') << stats->sample_count
              << " samples\n";

    // iostream with boost::format
    std::cerr << boost::format("at %p/%s: mean value %.3f of %4d samples\n")
                % stats % stats->name % stats->mean % stats->sample_count;
}

Andere Tipps

Es ist einfach zu ausführlich.

Ponder die iostream für Sie wie folgt vorgehen (in ähnlicher Weise für scanf) konstruieren:

// nonsense output, just to examplify
fprintf(stderr, "at %p/%s: mean value %.3f of %4d samples\n",
    stats, stats->name, stats->mean, stats->sample_count);

Das wäre erfordert so etwas wie:

std::cerr << "at " << static_cast<void*>(stats) << "/" << stats->name
          << ": mean value " << std::precision(3) << stats->mean
          << " of " << std::width(4) << std::fill(' ') << stats->sample_count
          << " samples " << std::endl;

String-Formatierung ist ein Fall, in dem Objekt-Orientiert kann und soll sein, für eine Formatierung DSL wich in Strings eingebettet. Betrachten Sie Lisp die format, Pythons printf-Stil Formatierung oder PHP, Bash, Perl, Ruby und ihre String Intrapolation.

iostream für diesen Anwendungsfall ist falsch, am besten.

Das Boost-Format Bibliothek eine typsichere, objektorientierte Alternative für printf-String-Formatierung und ist eine Ergänzung zu iostreams bereitstellt, die von den üblichen Ausführlichkeit Problemen nicht durch die geschickte% Verwendung Betreiber leiden. Ich empfehle, wenn man bedenkt es über Ebene C printf verwenden, wenn Sie mit Iostream Bediener Abneigung Formatierung <<.

Zurück in den schlechten alten Tagen hielt der C ++ Normenausschuss über mit der Sprache Ausmisten und iostreams ein sich bewegendes Ziel wurde. Wenn Sie iostreams verwendet, wurden Sie dann die Möglichkeit, jedes Jahr Teile des Codes oder so neu zu schreiben. Aus diesem Grund, habe ich immer stdio, die sich seit 1989 nicht verändert hat.

Wenn ich Sachen heute tat, würde ich iostreams verwenden.

Wenn, wie ich, Sie C gelernt, bevor C ++ zu lernen, scheinen die stdio Bibliotheken natürlicher zu verwenden. Es gibt Vor-und Nachteile für Iostream vs. stdio aber ich vermisse printf (), wenn Iostream verwendet wird.

Im Prinzip würde ich iostreams verwenden, in der Praxis ich zu viel formatiert Dezimalzahlen, etc., die iostreams zu unleserlich machen, so dass ich stdio. Boost :: Format ist eine Verbesserung, aber nicht sehr motivierend genug für mich. In der Praxis ist stdio fast typsicher, da die meisten modernen Compiler tun Argument Überprüfung trotzdem.

Es ist ein Gebiet, wo ich mit einem der Lösungen immer noch nicht ganz zufrieden bin.

Für binäre IO, neige ich stdio die fread und fwrite zu verwenden. Für formatiert Sachen werde ich in der Regel IO-Stream verwenden, obwohl als Mikael sagte, nicht-triviale (non-default?) Formatierung ein PITA werden kann.

Ich werde die beiden Mainstream-Bibliotheken aus der C ++ Standardbibliothek werden verglichen wird.

Sie sollten nicht im C-Stil-Format-String-basierten String-Verarbeitung-Routinen in C ++.

verwenden

Mehrere Gründe existieren, deren Nutzung Mīt:

  • Nicht typsicher
  • Sie können nicht nicht-POD-Typen variadische Argumentlisten übergeben (das heißt, weder scanf + co., Noch zu printf + co.), oder geben Sie die dunkele Festung des undefinierten Verhaltens
  • Leicht zu bekommen falsch:
    • Sie müssen verwalten den Format-String zu halten und die "Wert-Argument-Liste" in sync
    • Sie müssen synchron halten richtig

Subtle Fehler an entfernten Orten eingeführt

Es ist nicht nur die printf in selbst, das ist nicht gut. Software wird alt und wird überarbeitet und modifiziert, und Fehler können von entfernten Orten eingeführt werden. Angenommen, Sie haben

.

// foo.h
...
float foo;
...

und irgendwo ...

// bar/frob/42/icetea.cpp
...
scanf ("%f", &foo);
...

Und drei Jahre später feststellen, dass foo sollten einigen benutzerdefinierten Typ sein ...

// foo.h
...
FixedPoint foo;
...

aber irgendwo ...

// bar/frob/42/icetea.cpp
...
scanf ("%f", &foo);
...

... dann Ihr alter printf / scanf noch kompilieren, mit der Ausnahme, dass Sie jetzt zufällig segfaults bekommen und Sie nicht mehr, warum.

Ausführlichkeit von iostreams

Wenn Sie denken, printf () ist weniger ausführlich, dann gibt es eine gewisse Wahrscheinlichkeit, dass Sie ihre Iostream die nicht die volle Kraft an. Beispiel:

  printf ("My Matrix: %f %f %f %f\n"
          "           %f %f %f %f\n"
          "           %f %f %f %f\n"
          "           %f %f %f %f\n",
          mat(0,0), mat(0,1), mat(0,2), mat(0,3), 
          mat(1,0), mat(1,1), mat(1,2), mat(1,3), 
          mat(2,0), mat(2,1), mat(2,2), mat(2,3), 
          mat(3,0), mat(3,1), mat(3,2), mat(3,3));

Vergleichen Sie das iostreams zur Verwendung von rechts:

cout << mat << '\n';

Sie haben einen richtigen Überlastung für Betreiber definieren << was in etwa die Struktur des printf-Dingens, aber der wesentliche Unterschied ist, dass Sie jetzt etwas wiederverwendbar und typsichere haben; Sie können natürlich auch etwas wiederverwendbar für printf-likes machen, aber dann haben Sie printf wieder (was ist, wenn Sie die Matrixelemente mit dem neuen FixedPoint ersetzen?), von anderen nicht-Trivialitäten, z.B. Sie müssen FILE * Griffe um passieren.

C-Stil-Format-Strings sind nicht besser für L18N als iostreams

Beachten Sie, dass Format-Strings oft werden gedacht, die Rettung mit Internationalisierung zu sein, aber sie sind nicht überhaupt besser als Iostream in dieser Hinsicht:

printf ("Guten Morgen, Sie sind %f Meter groß und haben %d Kinder", 
        someFloat, someInt);

printf ("Good morning, you have %d children and your height is %f meters",
        someFloat, someInt); // Note: Position changed.

// ^^ not the best example, but different languages have generally different
//    order of "variables"

d., Im alten Stil C-Format-Strings fehlen Positionsinformationen so viel wie iostreams tun.

Sie können steigern betrachten wollen :: Format , die bietet Unterstützung, um die Position im Format-String explizit für die Angabe. Aus ihren Beispielen Abschnitt:

cout << format("%1% %2% %3% %2% %1% \n") % "11" % "22" % "333"; // 'simple' style.

Einige printf-Implementierungen bieten Positionsargumente, aber sie sind nicht-Standard.

Soll ich nie Verwendung im C-Format Format-Strings?

Neben Leistung (wie von Jan Hudec weist darauf hin), ich sehe keinen Grund. Aber bedenken Sie:

  

„Wir sollten über kleine Effizienz, sagen sie etwa 97% der Zeit vergessen: vorzeitige Optimierung ist die Wurzel aller Übel. Doch wir sollten nicht unsere Chancen in diesem kritischen 3% verzichten. Ein guter Programmierer nicht in Selbstzufriedenheit durch eine solche Argumentation einlullen lassen, wird er klug sein, genau auf den kritischen Code zu suchen; aber erst, nachdem der Code identifiziert worden ist“- Knuth

und

  

„Bottlenecks treten in überraschenden Orten, also nicht auf den zweiten erraten versuchen und in einer Geschwindigkeit Hack setzen, bis Sie bewiesen haben, das ist, wo der Engpass ist.“ - Pike

Ja, printf-Implementierungen sind in der Regel schneller als iostreams sind in der Regel schneller als boost :: Format (von einem kleinen und spezifischen Benchmark ich schrieb, aber es sollte insbesondere auf die Situation weitgehend abhängen: wenn printf = 100%, dann Iostream = 160% und boost :: format = 220%)

Aber nicht blind unterlassen, darüber nachzudenken: Wie viel Zeit Sie wirklich ausgeben Textverarbeitung? Wie lange dauert das Programm läuft vor dem Verlassen? Ist es überhaupt relevant C-Stil-Format-Strings zu fallen zurück, lose ArtSicherheit, verringert refactorbility, erhöhen Wahrscheinlichkeit sehr subtile Fehler, die sich jahrelang verstecken und kann sich nur recht offenbaren in Ihren Favoriten Gesicht Kunden?

Persönlich würde ich zurückgreifen nicht, wenn ich nicht mehr als 20% Speedup gewinnen. Aber weil meine Anwendungen verbringen fast ihre ganze Zeit auf andere Aufgaben als String-Verarbeitung, hatte ich nie. einige Parser Ich schrieb fast ihre ganze Zeit auf Stringverarbeitung ausgeben, aber ihre Gesamtlaufzeit ist so klein, dass es nicht wert, die Prüfung und Verifizierung Aufwand ist.

Einige Rätsel

Schließlich möchte ich einige Rätsel voreinzustellen:

alle Fehler finden, da der Compiler nicht (er kann nur vorschlagen, wenn er schön ist):

shared_ptr<float> f(new float);
fscanf (stdout, "%u %s %f", f)

Wenn nichts anderes, was ist los mit diesem?

const char *output = "in total, the thing is 50%"
                     "feature  complete";
printf (output);

Während es viele Vorteile für die C ++ iostreams API, ein signifikantes Problem ist hat, ist um i18n. Das Problem ist, dass die Reihenfolge der Parameter Substitutionen auf der Kultur variieren können. Das klassische Beispiel ist so etwas wie:

// i18n UNSAFE 
std::cout << "Dear " << name.given << ' ' << name.family << std::endl;

Während die für Englisch arbeitet, in der chinesischen der Familienname ist an erster Stelle.

Wenn es darum geht, den Code für ausländische Märkte zu übersetzen, Schnipsel zu übersetzen ist voller Gefahren so neue l10ns können Änderungen an dem Code erfordern und nicht nur verschiedene Saiten.

boost :: Format scheint die besten von stdio zu kombinieren (ein einzelnen Format-String, der die Parameter in einer anderen Reihenfolge verwenden kann, dann erscheinen sie) und iostreams (Typsicherheit, Erweiterbarkeit).

Ich benutze iostreams, vor allem, weil das macht es einfacher, mit dem Strom fiedeln später (wenn ich es brauche). Zum Beispiel könnten Sie, dass Sie die Ausgabe in einigen Trace-Fenstern angezeigt werden sollen herausfinden - das ist relativ einfach mit cout und cerr zu tun. Sie können vom Kurs abgekommen, Geige mit Rohren und Sachen auf Unix, aber das ist nicht so portabel.

ich liebe printf-ähnliche Formatierung, so dass ich in der Regel formatiert einen String zuerst, und dann in den Puffer senden. Mit Qt, verwende ich oft QString :: sprintf (obwohl sie mit empfehlen < a href = "http://doc.trolltech.com/4.4/qstring.html#arg-10" rel = "nofollow noreferrer"> QString :: arg statt). Ich habe unter Boost.Format als gut, aber die Syntax bekommen konnte (zu viel% s) nicht wirklich genutzt. Ich sollte es wirklich einen Blick geben, though.

Was ich vermisse über die iolibraries ist die formatierte Eingabe.

iostreams nicht eine schöne Art und Weise scanf zu replizieren () und sogar Auftrieb hat nicht die erforderliche Erweiterung für die Eingabe.

stdio ist besser für das Lesen von Binär-Dateien (wie Blöcke in einen Vektor freading und mit .resize () etc.). Siehe die read_rest Funktion in file.hh in http://nuwen.net/libnuwen.html für eine Beispiel.

C ++ Streams können auf viele Bytes ersticken, wenn binäre Dateien Lesen eines falschen eof verursacht.

Da iostreams ein Standard geworden sind, können Sie sie verwenden sollten, zu wissen, dass der Code sicher mit neueren Versionen von Compiler arbeiten. Ich denke, heute die meisten der Compiler wissen sehr gut über iostreams und es sollte nicht sein Problem mit ihnen.

Wenn Sie aber mit * printf-Funktionen bleiben wollen es kann kein Problem meiner Meinung nach sein.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top