C ++ Äquivalent zu sprintf?

82

Ich weiß, dass dies std::coutdas C ++ - Äquivalent von ist printf.

Was ist das C ++ - Äquivalent sprintf?

lital maatuk
quelle

Antworten:

66

std::ostringstream

Beispiel:

#include <iostream>
#include <sstream> // for ostringstream
#include <string>

int main()
{
  std::string name = "nemo";
  int age = 1000;
  std::ostringstream out;  
  out << "name: " << name << ", age: " << age;
  std::cout << out.str() << '\n';
  return 0;
}

Ausgabe:

name: nemo, age: 1000
Vijay Mathew
quelle
3
Ich glaube nicht, dass sprintf an stdout schreibt. Ich würde die Einfügeanweisung oben entfernen.
Raffi Khatchadourian
78
Wie ist das überhaupt aus der Ferne ähnlich sprintf (...)? Sie können die Daten nicht willkürlich formatieren. Sie müssen sich darauf verlassen, dass der Typ bekannt ist, wenn Sie ihn mit dem <<Operator in den Stream einspeisen.
Andon M. Coleman
Ich muss @ AndonM.Coleman in diesem Punkt zustimmen. Dies ist nicht wirklich ein Sprintf-Ersatz. Das wäre eher so, aber das ist Qt.
lpapp
Wie @vinkris in seiner Antwort sagt, erreicht iomanip die Formatierung. Anstatt auf stdoit zu drucken, würde ich "result = out.str ()" sagen.
Dmitri
sprintf / snprintf ermöglicht das Formatieren und Drucken in einem vom Benutzer zugewiesenen Zeichenarray, das sich möglicherweise auf einem Stapel befindet. Bei snprintf () wird sichergestellt, dass kein Überlauf auftritt. Hier weisen wir mehrfach Speicher zu und der Anrufer hat keinen direkten Zugriff darauf. Müssen in eine Zeichenfolge konvertieren, um die Ausgabe zu erhalten. Ein std :: ostream mit einem benutzerdefinierten std :: streambuf, der Benutzerpuffer benötigt, passt besser zusammen - natürlich erhöht die Konstruktion / Zerstörung von ostream / streambuf die Effizienz.
MGH
34

Update, August 2019:

Es sieht so aus, als hätte C ++ 20 std::format. Die Referenzimplementierung ist {fmt} . Wenn Sie printf()jetzt nach einer Alternative suchen , wird dies zum neuen "Standard" -Ansatz und ist eine Überlegung wert.

Original:

Verwenden Sie Boost.Format . Es hat eine printfähnliche Syntax, Typensicherheit, std::stringErgebnisse und viele andere nützliche Dinge. Du wirst nicht zurück gehen.

janm
quelle
14
... es sei denn, Sie sind besorgt über die Größe Ihrer ausführbaren Datei ..: P
Pradyunsg
Wie stark würde sich das auswirken? Die Boost-Abhängigkeit wäre nur Header, keine Verknüpfung, richtig?
Ken Williams
1
@ KenWilliams Ja, Boost.Format ist nur ein Header. Ein einfacher "Hallo Welt" -Test auf meinem Mac erhöht sich von 10 KB auf 78 KB. In einem realen Projekt wird die zusätzliche Größe über die Kompilierungseinheiten hinweg abgeschrieben (geben Sie die richtigen Linkeroptionen an), und die Typensicherheit bringt weitere Vorteile.
Janm
17

sprintf funktioniert gut in C ++.

Steve Rowe
quelle
4
Ich denke, das OP bedeutete eher STL als C ++.
Jean-Michaël Celerier
4
Bei sprintf müssen Sie den Zeichenpuffer zuweisen. Ich möchte so etwas wie die "append" -Methode von "std :: string", mit der ich formatierte Daten hinzufügen und mich um die Zuordnung hinter den Kulissen kümmern kann.
Victor Eijkhout
7

Sie können die iomanip-Headerdatei verwenden, um den Ausgabestream zu formatieren. Überprüfen Sie dies !

vinkris
quelle
Warum hat jemand dies abgelehnt? Ist iomanip nicht die reine C ++ - Methode, um Formatierungen in Streams zu erreichen? Ich denke, das Ziel hier ist es, das Speichern von Daten in Zeichenfolgen im C-Stil zu vermeiden, was mit iomanip erreicht wird.
Dmitri
7

Hier ist eine nette Funktion für einen C ++ Sprintf. Streams können hässlich werden, wenn Sie sie zu stark verwenden.

std::string string_format(const std::string &fmt, ...) {
    int size=100;
    std::string str;
    va_list ap;

    while (1) {
        str.resize(size);
        va_start(ap, fmt);
        int n = vsnprintf(&str[0], size, fmt.c_str(), ap);
        va_end(ap);
   
        if (n > -1 && n < size) {
            str.resize(n); // Make sure there are no trailing zero char
            return str;
        }
        if (n > -1)
            size = n + 1;
        else
            size *= 2;
    }
}

In C ++ 11 und höher wird garantiert, dass std :: string zusammenhängenden Speicher verwendet, der mit endet. Daher ist '\0'es legal, ihn in char *using umzuwandeln &str[0].

Es wurde darauf hingewiesen, dass verschiedene Argumente nicht der Referenzübergabe folgen sollen, und c ++ ist gut darin, Zeichenfolgen nicht zu kopieren, wenn dies nicht erforderlich ist. In diesem Fall wird das Problem behoben.

std::string string_format(std::string fmt, ...) {
Erik Aronesty
quelle
Sehr schöne Lösung! Ich habe es hier angepasst: stackoverflow.com/a/3742999/15161, um die Verwendung besser sprintfanzupassen.
Slashmais
10
Illegal, aber: (char*) str.c_str()wirft weg const.
MSalters
Außerdem lauert ein Problem mit dem Pufferüberlauf
Barney Szabolcs,
@ MSalters Richtig. In C ++ 11 gibt es einen legalen Weg, dies zu tun.
Whitequark
@whitequark: Fühlen Sie sich frei, das als Antwort hinzuzufügen. Beim Stapelüberlauf bleiben gute Fragen offen, um neue Antworten zu ermöglichen.
MSalters
0

Verwenden Sie einen Stringstream, um den gleichen Effekt zu erzielen. Sie können auch <cstdio>snprintf einschließen und weiterhin verwenden.

Königlichkeit
quelle
0

Je nachdem, was genau Sie planen sprintf(), std::to_string()kann dies nützlich und idiomatischer sein als andere Optionen:

void say(const std::string& message) {
 // ...
}

int main() {
  say(std::to_string(5));
  say("Which is to say " + std::to_string(5) + " words");
}

Der Hauptvorteil von std::to_string()IMHO ist, dass es einfach erweitert werden kann, um zusätzliche Typen zu unterstützen, sprintf()die nicht einmal von Stringing träumen können - ähnlich wie bei Java Object.toString().

Guss
quelle