C ++ Äquivalent zu sprintf?


82

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

Was ist das C ++ - Äquivalent sprintf?

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

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.


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 ++.


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 !


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, ...) {

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.


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().

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.