Ich verstehe, dass dies string
ein Mitglied des std
Namespace ist. Warum tritt also Folgendes auf?
#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, wird myString
eine scheinbar zufällige Zeichenfolge mit 3 Zeichen gedruckt, wie in der obigen Ausgabe.
Antworten:
Es wird kompiliert, weil
printf
es nicht typsicher ist, da es variable Argumente im C-Sinne 1 verwendet .printf
hat keine Option fürstd::string
, nur eine Zeichenfolge im C-Stil. Wenn Sie etwas anderes anstelle dessen verwenden, was erwartet wird, erhalten Sie definitiv nicht die gewünschten Ergebnisse. Es ist eigentlich undefiniertes Verhalten, also könnte überhaupt alles passieren.Der einfachste Weg, dies zu beheben, da Sie C ++ verwenden, besteht darin, es normal zu drucken
std::cout
, da diesstd::string
durch Überladen von Operatoren unterstützt wird:Wenn Sie aus irgendeinem Grund die Zeichenfolge im C-Stil extrahieren müssen, können Sie die
c_str()
Methode verwendenstd::string
, um eine Zeichenfolge zu erhaltenconst char *
, die nullterminiert ist. Anhand Ihres Beispiels:Wenn Sie eine Funktion wünschen, die ähnlich ist
printf
, aber sicher eingibt, schauen Sie sich verschiedene Vorlagen an (C ++ 11, unterstützt von allen wichtigen Compilern ab MSVC12). Ein Beispiel dafür finden Sie hier . Es gibt nichts, von dem ich weiß, dass es so in der Standardbibliothek implementiert ist, aber es könnte speziell in Boost vorhanden seinboost::format
.[1]: Dies bedeutet, dass Sie eine beliebige Anzahl von Argumenten übergeben können. Die Funktion ist jedoch darauf angewiesen, dass Sie die Anzahl und den Typ dieser Argumente angeben. Im Fall von
printf
bedeutet dies eine Zeichenfolge mit codierten Typinformationen wie%d
Bedeutungint
. Wenn Sie über den Typ oder die Nummer lügen, hat die Funktion keine Standardmethode, obwohl einige Compiler die Möglichkeit haben, zu überprüfen und Warnungen zu geben, wenn Sie lügen.quelle
Bitte nicht benutzen
printf("%s", your_string.c_str());
Verwenden Sie
cout << your_string;
stattdessen. Kurz, einfach und typsicher. Wenn Sie C ++ schreiben, möchten Sie dies im Allgemeinenprintf
vollständig vermeiden - es ist ein Überbleibsel von C, das in C ++ selten benötigt oder nützlich ist.Es gibt zahlreiche Gründe , warum Sie
cout
stattdessen verwenden solltenprintf
. Hier eine Auswahl einiger der offensichtlichsten:printf
ist nicht typsicher. Wenn der von Ihnen übergebene Typ von dem im Konvertierungsspezifizierer angegebenen Typ abweicht,printf
wird versucht, alles, was auf dem Stapel gefunden wird, so zu verwenden, als wäre es der angegebene Typ, was zu einem undefinierten Verhalten führt. Einige Compiler können unter bestimmten Umständen davor warnen, aber einige Compiler können / werden überhaupt nicht und keiner kann unter allen Umständen.printf
ist nicht erweiterbar. Sie können nur primitive Typen übergeben. Der Satz von Conversion-Spezifizierern, den er versteht, ist in seiner Implementierung fest codiert, und Sie können keine weiteren / anderen hinzufügen. Die meisten gut geschriebenen C ++ - Programme sollten diese Typen hauptsächlich verwenden, um Typen zu implementieren, die auf das zu lösende Problem ausgerichtet sind.Dies erschwert eine anständige Formatierung erheblich. Als offensichtliches Beispiel möchten Sie beim Drucken von Zahlen zum Lesen normalerweise alle paar Ziffern Tausende Trennzeichen einfügen. Die genaue Anzahl der Ziffern und die als Trennzeichen verwendeten Zeichen variieren, werden aber
cout
auch abgedeckt. Beispielsweise:Das namenlose Gebietsschema (das "") wählt ein Gebietsschema basierend auf der Konfiguration des Benutzers aus. Daher wird dies auf meinem Computer (konfiguriert für US-Englisch) als gedruckt
123,456.78
. Für jemanden, der seinen Computer für (sagen wir) Deutschland konfiguriert hat, würde er so etwas wie ausdrucken123.456,78
. Für jemanden, der es für Indien konfiguriert hat, würde es als1,23,456.78
(und natürlich gibt es viele andere) ausgedruckt. Mitprintf
bekomme ich genau ein Ergebnis :123456.78
. Es ist konsequent, aber es ist konsequent für alle überall falsch . Im Wesentlichen besteht die einzige Möglichkeit, dies zu umgehen, darin, die Formatierung separat durchzuführen und das Ergebnis dann als Zeichenfolge an zu übergebenprintf
, da der Jobprintf
selbst einfach nicht korrekt ausgeführt wird.printf
können Formatzeichenfolgen ziemlich unlesbar sein. Selbst unter C-Programmierern, dieprintf
praktisch jeden Tag arbeiten, müssten mindestens 99% nachschlagen, um sicherzugehen, was das#
In%#x
bedeutet und wie sich das von dem unterscheidet, was das#
In%#f
bedeutet (und ja, sie bedeuten ganz andere Dinge ).quelle
#include <string>
. VC ++ hat einige Kuriositäten in seinen Headern, mit denen Sie einen String definieren, aber nicht an ihn senden könnencout
, ohne den<string>
Header einzuschließen.cout
ist das langsamer, weil Sie dort verwendet haben,std::endl
wo Sie es nicht sollten.Verwenden
myString.c_str()
Sie diese Option, wenn eine c-ähnliche Zeichenfolge (const char*
) mit printf verwendet werden sollVielen Dank
quelle
Verwenden Sie das Beispiel std :: printf und c_str ():
quelle
Der Hauptgrund ist wahrscheinlich, dass eine C ++ - Zeichenfolge eine Struktur ist, die einen Wert für die aktuelle Länge enthält, nicht nur die Adresse einer Zeichenfolge, die mit einem 0-Byte abgeschlossen ist. Printf und seine Verwandten erwarten, eine solche Sequenz zu finden, keine Struktur, und werden daher durch C ++ - Zeichenfolgen verwirrt.
Wenn ich für mich selbst spreche, glaube ich, dass printf einen Platz hat, der nicht einfach mit syntaktischen C ++ - Funktionen gefüllt werden kann, genauso wie Tabellenstrukturen in HTML einen Platz haben, der nicht einfach mit divs gefüllt werden kann. Wie Dykstra später über das goto schrieb, hatte er nicht die Absicht, eine Religion zu gründen, und argumentierte wirklich nur dagegen, sie als Kludge zu verwenden, um schlecht gestalteten Code auszugleichen.
Es wäre sehr schön, wenn das GNU-Projekt die printf-Familie zu ihren g ++ - Erweiterungen hinzufügen würde.
quelle
Printf ist eigentlich ziemlich gut zu verwenden, wenn es auf die Größe ankommt. Das heißt, wenn Sie ein Programm ausführen, bei dem der Speicher ein Problem darstellt, ist printf tatsächlich eine sehr gute und unterbewertete Lösung. Cout verschiebt im Wesentlichen Bits, um Platz für die Zeichenfolge zu schaffen, während printf nur einige Parameter aufnimmt und diese auf dem Bildschirm druckt. Wenn Sie ein einfaches Hallo-Welt-Programm kompilieren würden, wäre printf in der Lage, es in weniger als 60.000 Bit zu kompilieren, im Gegensatz zu cout. Das Kompilieren würde über 1 Million Bit erfordern.
Für Ihre Situation empfehlen wir die Verwendung von cout, einfach weil es viel bequemer zu verwenden ist. Obwohl ich argumentieren würde, dass printf etwas Gutes zu wissen ist.
quelle
printf
akzeptiert eine variable Anzahl von Argumenten. Diese können nur POD-Typen (Plain Old Data) haben. Code, der alles andere als PODprintf
nur zum Kompilieren übergibt, da der Compiler davon ausgeht, dass Sie das richtige Format haben.%s
bedeutet, dass das jeweilige Argument ein Zeiger auf a sein sollchar
. In deinem Fall ist es einstd::string
nichtconst char*
.printf
weiß es nicht, weil der Argumenttyp verloren geht und aus dem Formatparameter wiederhergestellt werden soll. Wenn Sie diesesstd::string
Argument inconst char*
den resultierenden Zeiger umwandeln, verweist es auf einen irrelevanten Speicherbereich anstelle der gewünschten C-Zeichenfolge. Aus diesem Grund druckt Ihr Code Kauderwelsch aus.Dies
printf
ist zwar eine ausgezeichnete Wahl zum Ausdrucken von formatiertem Text (insbesondere, wenn Sie eine Auffüllung beabsichtigen), kann jedoch gefährlich sein, wenn Sie keine Compiler-Warnungen aktiviert haben. Aktivieren Sie immer Warnungen, da solche Fehler leicht vermieden werden können. Es gibt keinen Grund, den ungeschicktenstd::cout
Mechanismus zu verwenden, wenn dieprintf
Familie dieselbe Aufgabe viel schneller und schöner erledigen kann. Stellen Sie einfach sicher, dass Sie alle Warnungen (-Wall -Wextra
) aktiviert haben und Sie werden gut sein. Wenn Sie Ihre eigene benutzerdefinierteprintf
Implementierung verwenden, sollten Sie diese mit dem__attribute__
Mechanismus deklarieren, mit dem der Compiler die Formatzeichenfolge anhand der angegebenen Parameter überprüfen kann .quelle