printf mit std::string?
Mein Verständnis ist, dass string
ist ein Mitglied der std
namespace, also warum die folgenden Ereignisse?
#include <iostream>
int main()
{
using namespace std;
string myString = "Press ENTER to quit program!";
cout << "Come up and C++ me some time." << endl;
printf("Follow this command: %s", myString);
cin.get();
return 0;
}
Jedes mal, wenn das Programm ausgeführt wird, myString
druckt eine scheinbar zufällige Zeichenkette von 3 Zeichen, wie in der obigen Ausgabe.
- Nur, damit Sie wissen, eine Menge von Menschen criticize das Buch. Das kann ich verstehen, da gibt es nicht viel über das Objekt-orientierte Programmierung, aber ich glaube nicht, dass es so schlimm wie Leute behaupten.
- ouf! gut, es ist gut, dies im Auge behalten, während ich meinen Weg durch das Buch. Ich bin sicher, es wird nicht die einzige C++ - Buch, das ich Lesen werden im Laufe des nächsten Jahres oder so, also ich hoffe es tut nicht zu viel damange 🙂
- Mit der höchsten compiler-Warnung würde Ihre Frage zu beantworten - wenn kompilieren mit gcc. Wie MSVC übernimmt dies - ich weiß es nicht.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Es kompiliert, weil
printf
ist nicht typsicher, da es verwendet eine variable Argumente in der C Sinn1.printf
hat keine option fürstd::string
nur ein C-Stil-string. Mit etwas anderes statt, was erwartet wird definitiv nicht geben Ihnen die Ergebnisse, die Sie wollen. Es ist tatsächlich ein Undefiniertes Verhalten, so etwas überhaupt passieren könnte.Die einfachste Möglichkeit dieses Problem zu beheben, da bist du mit C++, druckt er es normal mit
std::cout
, dastd::string
unterstützt, die durch operator-überladung:Wenn, aus irgendeinem Grund, müssen Sie extrahieren Sie die C-Stil-string, können Sie die
c_str()
Methode derstd::string
zu bekommenconst char *
ist null-terminiert. Mit deinem Beispiel:Wenn Sie möchten, eine Funktion, die wie
printf
, aber geben Sie sicher, Blick in variadic templates (C++11, unterstützt alle gängigen Compiler, wie der MSVC12). Sie finden ein Beispiel für eine hier. Es gibt nichts, was ich wissen umgesetzt, so dass in der standard-Bibliothek, aber es könnte sein, Boost, speziellboost::format
.[1]: Dies bedeutet, dass Sie passieren kann eine beliebige Anzahl von Argumenten, sondern um die Funktion stützt sich auf Sie sagen, es die Anzahl und die Typen dieser Argumente. Im Fall von
printf
bedeutet, dass ein string mit den kodierten Typ-Informationen wie%d
Bedeutungint
. Wenn Sie Lügen über den Typ oder die Anzahl, die Funktion hat keine standard-Möglichkeit zu wissen, obwohl einige Compiler haben die Möglichkeit, zu überprüfen und geben Warnungen, wenn Sie Lügen.cout
für die Zeichenfolge sowie?Verwenden Sie bitte nicht
printf("%s", your_string.c_str());
Verwenden
cout << your_string;
statt. Kurze, einfache und typesafe. In der Tat, wenn Sie das schreiben von C++, die Sie wollen in der Regel vermeidenprintf
ganz-es ist ein Relikt aus C, die nur selten benötigt oder sinnvoll in C++.Als zu warum, die Sie verwenden sollten
cout
stattprintf
, die Gründe sind zahlreich. Hier ist eine Auswahl von ein paar der offensichtlichsten:printf
ist nicht Typ-sicher. Wenn der Typ übergeben Sie unterscheidet sich von der, in der umwandlungsspezifikator,printf
wird versuchen zu verwenden, was es findet auf dem Stapel, als ob es dem angegebenen Typ, was zu undefiniertem Verhalten. Einige Compiler warnen, dass dies unter bestimmten Umständen, aber von einigen Compilern nicht/wird nicht auf allen, und keiner ist, unter allen Umständen.printf
ist nicht erweiterbar. Sie können nur primitive Typen zu. Der Satz von umwandlungsspezifikationen es versteht, ist hard-coded in der Umsetzung, und es gibt keine Möglichkeit für Sie, mehr hinzufügen/andere. Die meisten gut geschriebene C++ sollte die Verwendung dieser Typen in Erster Linie zu implementieren-Typen orientiert, das problem gelöst zu werden.Macht es anständige Formatierung viel schwieriger. Für ein offensichtliches Beispiel, wenn Sie drucken wollen, zahlen für die Menschen zu Lesen, Sie in der Regel einfügen möchten Tausendertrennzeichen alle paar Ziffern. Die genaue Anzahl der Ziffern und der Zeichen, die als Trennzeichen variiert, aber
cout
hat, dass abgedeckt. Zum Beispiel:Den namenlosen Gebietsschema (die "") nimmt eine Gebietsschema, basierend auf der Konfiguration des Benutzers. Also, auf meinem Rechner (Konfiguration für US-Englisch) diese Drucke als
123,456.78
. Für jemand, der hat Ihr computer so konfiguriert ist, für (sagen wir) Deutschland, würde es ausdrucken, so etwas wie123.456,78
. Für jemanden, der es konfiguriert für Indien, es würde ausdrucken1,23,456.78
(und natürlich gibt es viele andere). Mitprintf
bekomme ich genau ein Ergebnis:123456.78
. Es ist konsequent, aber es ist konsequent falsch für überall und jedermann. Im wesentlichen die einzige Möglichkeit, das zu umgehen, besteht darin, die Formatierung getrennt, dann das Ergebnis als string zuprintf
, weilprintf
sich einfach nicht tun die Arbeit richtig zu machen.printf
format-strings können sehr unleserlich. Auch unter C-Programmierern, dieprintf
praktisch jeden Tag, ich denke, mindestens 99% brauchen würde, um zu sehen die Dinge, um sicher zu sein, was die#
im%#x
bedeutet, und wie, das unterscheidet sich von dem, was die#
im%#f
bedeutet (und ja, Sie bedeuten völlig unterschiedliche Dinge sind).cout << myString << endl;
ich die folgende Fehlermeldung:Error 1 error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'std::string' (or there is no acceptable conversion)
#include <string>
. VC++ hat einige Merkwürdigkeiten in seinem Header, mit denen Sie definieren einen string, aber nicht senden Sie es zucout
, ohne die<string>
header.cout
ist langsamer, es ist, weil Sie verwendet habenstd::endl
wo Sie nicht sollte.printf
Familie, dass C++ "geerbt" von C.printf
werden, um thread-sicher, aber nicht alle Systeme vollständig konform mit POSIX (einige, natürlich nicht selbst versuchen). Es ist nicht klar genug, was meinen Sie mit "besser" zu kommentieren sinnvoll auf. Am Ende kommt es auf eine Sache, aber: ja, es gibt zumindest Fälle, in denen es zumindest einige vernünftige argument zugunsten der Verwendung vonprintf
--aber solche Fälle sind viel seltener, als manche Menschen denken, und der Fall ist noch nicht einmal in der Nähe.printf
ist die Antwort, die jemand fragte, eine lausige Frage.cout
ist das Schlimmste Merkmale C++ bietet.gcc
mit allen warn-Schalter aktiviert. Es ist nichts mehr sicher und besonders bequemer: 100% typesafe, überprüfen argument zählen. Formatierung mitcout
ist ein horror - besonders für lange log-Dateien Einträge. Ich bin immer lachen, wenn die C++cout << "Hallo"
oder eine Zahl. Aber tun Sie es mit 30 Argumente, [da Sprach ich für eine log]...gcc
warnt mich schon während der Zusammenstellung. Wenn ich nur daran denke über die Lösung mitcout
und die rudimentären Methoden, die ich krank.verwenden
myString.c_str()
wenn Sie möchten, eine c-like string (const char*
) zu verwenden mit printfDank
Verwenden std::printf und c_str()
Beispiel:
Printf ist eigentlich Recht gut zu verwenden, wenn die Größe ankommt. Das heißt, wenn Sie ein Programm ausführen, wo der Speicher ein Problem ist, dann von printf () ist eigentlich eine sehr gute und unter-rater-Lösung. Cout im wesentlichen verschiebt bits, um Platz zu machen für die Zeichenfolge, während printf () braucht nur in irgendeine Art von Parametern und druckt es auf dem Bildschirm. Wenn Sie, kompilieren Sie eine einfache "hello world" - Programm, printf in der Lage wäre, um es zu kompilieren, die in weniger als 60, 000 bits im Gegensatz zu cout, es würde über 1 Millionen bit zu kompilieren.
Für Ihre situation, id empfehlen die Verwendung von cout, weil es einfach viel bequemer zu verwenden. Obwohl, ich würde behaupten, dass printf ist etwas gut zu wissen.
Der Hauptgrund ist wohl, dass ein C++ - string ist eine Struktur enthält, die das aktuelle Länge Wert, nicht nur die Adresse, die einer Sequenz von Zeichen, abgeschlossen durch ein 0-byte. Printf und Ihre Angehörigen erwarten zu finden, wie eine Sequenz, nicht ein struct, und deshalb verwirrt von C++ - strings.
Sprechen für mich, glaube ich, dass printf, hat eine Stelle, die nicht leicht gefüllt werden, indem C++ syntaktische Funktionen, nur als Tisch-Strukturen in html haben einen Platz, der nicht so leicht gefüllt werden, indem divs. Als Dykstra, schrieb später über die "goto", er hatte nicht vor zu beginnen eine religion und war wirklich einzige argument gegen die Verwendung von es als eine Behelfslösung, um make-up für schlecht entwickelte code.
Wäre es ganz nett, wenn das GNU-Projekt möchte hinzufügen, die der printf-Familie, um Ihre g++ - Erweiterungen.
printf
akzeptiert eine variable Anzahl von Argumenten. Diese können nur Plain Old Data (POD) - Typen. Code, geht alles andere als POD zuprintf
nur compiliert, weil der compiler davon hast du dein format richtig.%s
bedeutet, dass das jeweilige argument ist eigentlich ein Zeiger auf einechar
. In Ihrem Fall ist es einestd::string
nichtconst char*
.printf
weiß es nicht, weil das argument type geht verloren und soll wiederhergestellt werden von den format-parameter. Beim drehen, dassstd::string
argument inconst char*
den resultierenden Zeiger auf einige irrelevante region Speicher anstelle von Ihrem gewünschten C-string. Deshalb Ihr code druckt Kauderwelsch.Während
printf
ist eine ausgezeichnete Wahl für den Druck von formatierten text, (vor allem, wenn Sie beabsichtigen, Polsterung), kann es gefährlich werden, wenn Sie noch nicht aktiviert compiler-Warnungen. Aktivieren Sie immer die Warnungen, weil dann Fehler wie diese sind leicht vermeidbar. Es gibt keinen Grund, die ungeschicktstd::cout
Mechanismus, wenn dieprintf
Familie tun können, die gleiche Aufgabe in einer viel schnelleren und schöneren Weg. Nur stellen Sie sicher, dass Sie aktiviert haben, werden alle Warnungen (-Wall -Wextra
) und Sie wird gut sein. In Fall, dass Sie verwenden Sie Ihre eigenen benutzerdefiniertenprintf
Umsetzung sollten Sie erklären es mit der__attribute__
Mechanismus, der ermöglicht, dass der compiler überprüfen Sie die format-string gegen die die Parameter.