Ist es eine schlechte Praxis, C-Features in C++ zu verwenden?

Lesezeit: 7 Minuten

Benutzer-Avatar
Gustav Puma

Zum Beispiel printf Anstatt von cout, scanf Anstatt von cinverwenden #define Makros usw.?

Ich würde nicht schlecht sagen, da es von der persönlichen Wahl abhängt. Meine Richtlinie lautet, wenn in C++ typsichere Alternativen verfügbar sind, verwenden Sie diese, da dies die Fehler im Code reduziert.

  • Gibt es online eine Dokumentation, in der ich sehen kann, ob eine Funktion typsicher ist oder nicht?

    – Gustavo Puma

    28. September 2010 um 13:22 Uhr

  • Wenn eine Funktion dauert void* Argumente oder gibt a zurück void* Ergebnis, dann ist es wahrscheinlich nicht typsicher. Eine Funktion mit einer variablen Argumentliste (wie z printf) ist im Allgemeinen auch nicht typsicher. Jederzeit müssen Sie verwenden sizeofist der Code wahrscheinlich nicht typsicher.

    – Christoph Johnson

    28. September 2010 um 13:35 Uhr


  • @ vash47: Mir ist keine Veröffentlichung bekannt, aber Sie können die folgenden Regeln als Anfang verwenden. Variadische Funktionen (wie printf & scanf) sind nicht typsicher, da der Compiler nicht überprüfen kann, ob die variadischen Argumente den richtigen Typ haben (mit Ausnahme einiger Sonderfälle). Makros sind aus demselben Grund auch weniger typsicher als Inline-Funktionen.

    – Bart van Ingen Schenau

    28. September 2010 um 13:36 Uhr

  • @ vash47: Es wird durch die Sprache impliziert. C++ versucht, das Umgehen der Eingabe zu erschweren. Naveen bezieht sich auf C++-Versionen der C-Äquivalente, die Templating und ähnliches beinhalten. Werfen Sie einen Blick auf Ihre lokale (und verzögerte) libstdc++.

    – Matt Tischler

    28. September 2010 um 13:50 Uhr

  • Es ist nicht nur Typsicherheit, sondern auch, wie erweiterbar es ist. Die meisten Compiler können zumindest mit einer Warnung diagnostizieren, ob die Argumente to printf sind von den richtigen Typen, aber selbst wenn der Compiler sicherstellt, dass Sie dort keinen Fehler machen, können Sie keinen benutzerdefinierten Typ übergeben, also überladen operator<< und verwenden cout ist eine Lösung für ein Problem, das eine Änderung der Syntax in C erfordert: std::cout << "My object is:" << obj << std::ednl; verglichen mit printf("My object is: "); obj.print(); printf("\n");

    – David Rodríguez – Dribeas

    28. September 2010 um 18:20 Uhr

Benutzer-Avatar
Eli Bendersky

Es kommt darauf an, welche Funktionen. Verwenden define Makros in C++ sind stark verpönt, und das aus gutem Grund. Sie können fast immer eine Verwendung von a ersetzen define Makro mit etwas wartbarerem und sichererem in C++ (Vorlagen, Inline-Funktionen usw.)

Streams hingegen werden von einigen Leuten zu Recht als sehr langsam beurteilt, und ich habe eine Menge gültigen und qualitativ hochwertigen C++-Code gesehen, der Cs verwendet FILE* stattdessen mit seinen zahlreichen Funktionen.

Und noch etwas: Bei allem Respekt vor der Fülle an Stream-Formatierungsmöglichkeiten, für Dinge wie einfache Debug-Ausdrucke ist IMHO die Prägnanz einfach nicht zu übertreffen printf und seine Formatzeichenfolge.

  • Kommt auf die Verwendung an. Boost (allgemein als die beste Bibliothekssammlung für C++ anerkannt) verwendet Makros in Hülle und Fülle.

    – Konrad Rudolf

    28. September 2010 um 13:18 Uhr

  • @Konrad, stimmte zu, obwohl Sie in jedem respektvollen C++-Leitfaden (wie Effective C++) ganze Abschnitte darüber finden, warum Makros in C++ nicht empfohlen werden. Außerdem, nach welchen Maßstäben ist Boost “am besten”? Würden Sie sagen, dass es am besten durch die Lesbarkeit seiner internen Implementierung ist?

    – Eli Bendersky

    28. September 2010 um 13:19 Uhr


  • @Eli: Ich habe über die Schnittstelle/Funktionalität gesprochen, nicht über die Implementierung. Aber Makros sind dafür relevant: Ohne die Verwendung von Makros könnte Boost (in einigen Fällen) nicht die Schnittstelle bereitstellen, die es bietet, und wäre (in anderen Fällen) erheblich schwieriger zu debuggen und zu warten. Obwohl die Implementierung von Boost oft chaotisch ist (hauptsächlich, um nicht konforme Compiler zu bedienen), machen Makros den Code rundum einfacher. Das gesagtich versuche wirklich, Makros wo möglich zu vermeiden (ich verwende sie überhaupt nicht in „normalem“ Code).

    – Konrad Rudolf

    28. September 2010 um 13:29 Uhr


  • @Eli: Irgendwie habe ich diesen Teil des Satzes (und die ganze Sache mit Vorlagen und Inline-Funktionen) komplett übersehen. dem kann ich jetzt nur zustimmen.

    – Konrad Rudolf

    28. September 2010 um 13:33 Uhr

  • Ich bin ein Fan von printf auch, aber Sie sollten es nicht empfehlen, ohne auf die Nachteile hinzuweisen: den Mangel an Typsicherheit und die Leichtigkeit, die Übereinstimmung zwischen Spezifikationen und Parametern durcheinander zu bringen.

    – Markieren Sie Lösegeld

    28. September 2010 um 15:43 Uhr

Solltest du unbedingt nutzen printf anstelle von cout. Letzteres tut lassen Sie die meisten oder alle Formatierungssteuerelemente vornehmen printf erlaubt, aber es tut dies in a Staatsbürgerlich Weg. Dh der aktuelle Formatierungsmodus wird als Teil des (globalen) Objekts gespeichert. Dies bedeutet, dass schlechter Code verschwinden kann cout in einem Zustand, in dem die nachfolgende Ausgabe falsch formatiert wird, es sei denn, Sie setzen die gesamte Formatierung jedes Mal zurück, wenn Sie sie verwenden. Es richtet auch Chaos bei der Thread-Nutzung an.

  • Amen, wir haben beide Kampfnarben davon, diese Position zu verteidigen 😉

    – Matt Tischler

    28. September 2010 um 13:53 Uhr

  • +1, ich stimme voll und ganz zu. Das Programmieren mit Nebeneffekten ist böse, und hier ist es ein Bibliotheksstandard, der dieses schlechte Verhalten auferlegt 🙁

    – Jens Gustedt

    28. September 2010 um 14:26 Uhr

  • Natürlich ist das gesamte Design von std::cout ist, dass es ein Objekt ist, das den Zustand speichert. Sein Hauptproblem ist das Fehlen eines Kopierctors; Sie sollten in der Lage sein, eine billige Kopie zu erstellen, den Status festzulegen, die Ausgabe durchzuführen und dann die Kopie zu verwerfen, ohne das Original zu beeinträchtigen.

    – MSalter

    28. September 2010 um 15:12 Uhr

  • @MSalters: Das wird viel komplizierter, wenn Sie das Puffern und die Beziehung zu Threads berücksichtigen. Ich bin mir sicher, dass dies mit einem gemeinsam genutzten versteckten internen Objekt erfolgen könnte, in dem das Puffern und Sperren stattfand, mit dem lokalen Status im Wrapper-Objekt, aber ich behaupte, dass es nur ein schlechtes Design ist.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    28. September 2010 um 16:42 Uhr

  • std::cout wie es heute gestaltet ist, ist in diesem Sinne schon kompliziert. Wenn der Formatiererstatus ein separates Objekt war, erlauben Sie Threads, unabhängige Objekte zu haben. Wenn überhaupt, das vereinfacht Multithread-Entwicklung.

    – MSalter

    30. September 2010 um 11:37 Uhr


Benutzer-Avatar
Justin Nießner

Ich würde sagen, die einzigen, die beim Mischen wirklich schädlich sind, sind die Paarungen zwischen ihnen malloc/free und new/delete.

Ansonsten ist es wirklich eine Sache des Stils … und obwohl C mit C++ kompatibel ist, warum sollten Sie die beiden Sprachen mischen wollen, wenn C++ alles hat, was Sie brauchen, ohne darauf zurückgreifen zu müssen?

Benutzer-Avatar
Konrad Rudolf

Für die meisten Fälle gibt es bessere Lösungen, aber nicht für alle.

Zum Beispiel verwenden die Leute ziemlich oft memcpy. Ich würde das fast nie tun (außer in Ja wirklich Low-Level-Code). Ich benutze immer std::copysogar auf Zeiger.

Dasselbe gilt für die Ein-/Ausgaberoutinen. Aber es stimmt manchmal, C-Stil printf ist wesentlich einfacher zu bedienen als cout (insbesondere beim Loggen). Wenn Boost.Format keine Option ist, verwenden Sie C.

#define ist eine ganz andere Bestie. Es ist nicht wirklich ein reines C-Feature, und es gibt viele legitime Anwendungen dafür in C++. (Aber viele mehr, die es nicht sind.)

Natürlich würden Sie es niemals verwenden, um Konstanten zu definieren (das ist was const ist für) noch um Inline-Funktionen zu deklarieren (use inline und Vorlagen!).

Andererseits ist es oft nützlich, Debugging-Assertionen zu generieren und allgemein als Codegenerierungstool. Zum Beispiel bin ich Unit-Testing-Klassen-Templates und ohne umfangreiche Verwendung von Makros wäre dies ein echter Schmerz in der * ss. Die Verwendung von Makros ist hier nicht schön, aber es spart buchstäblich Tausende von Codezeilen.

Benutzer-Avatar
Chris o

Für Zuweisungen würde ich die Verwendung von malloc/free ganz vermeiden und einfach bei new/delete bleiben.

Benutzer-Avatar
Ruel

Nicht wirklich, printf() ist ziemlich schneller als cout, und die c++ iostream-Bibliothek ist ziemlich groß. Dies hängt von den Benutzereinstellungen oder dem Programm selbst ab (wird es benötigt? usw.). Ebenfalls, scanf() ist nicht mehr geeignet, bevorzuge ich fgets().

  • Das ist falsch: printf schneller sein als cout ist eine urbane Legende. Dies hängt wirklich von der Implementierung der Standardbibliothek ab und davon, ob Streams gepuffert werden oder nicht (aber das gilt für C- und C++-Streams!). printf ist nicht generell schneller als cout. Es kann sogar umgekehrt sein. Außerdem, fgets und scanf sind ganz anders (scanf tut formatiert Eingang) und fgets kann ersetzt werden durch cin.

    – Konrad Rudolf

    28. September 2010 um 13:24 Uhr


  • ziemlich sicher meinte er fgets + sscanf

    – FastAl

    28. September 2010 um 14:01 Uhr

1187520cookie-checkIst es eine schlechte Praxis, C-Features in C++ zu verwenden?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy