C ++ odpowiednik sprintf?


84

Wiem, że std::coutjest to odpowiednik C ++ printf.

Jaki jest odpowiednik C ++ sprintf?

Odpowiedzi:


69

std::ostringstream

Przykład:

#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;
}

Wynik:

name: nemo, age: 1000

3
Nie sądzę, żeby Sprintf zapisywał na standardowe wyjście. Usunąłbym powyższe oświadczenie.
Raffi Khatchadourian

81
Jak to jest choć trochę podobne do sprintf (...)? Nie możesz sformatować danych w dowolny sposób, musisz polegać na znanym typie, gdy wprowadzasz je do strumienia za pomocą <<operatora.
Andon M. Coleman

1
Muszę się zgodzić z @ AndonM.Coleman w tej sprawie. To naprawdę nie jest zamiennik sprintów. To byłoby bardziej podobne, ale to jest Qt.
lpapp,

jak @vinkris mówi w swojej odpowiedzi, iomanip osiąga formatowanie. Zamiast drukować na stdoit, powiedziałbym "result = out.str ()".
Dmitri

sprintf / snprintf umożliwia formatowanie i drukowanie do tablicy znaków przydzielonej użytkownikowi, może znajdować się na stosie. W przypadku snprintf () zapewnia to brak przepełnienia. Tutaj alokujemy pamięć wielokrotnie i dzwoniący nie ma do niej bezpośredniego dostępu. Muszę przekonwertować na ciąg, aby uzyskać dane wyjściowe. Std :: ostream z niestandardowym std :: streambuf, który pobiera bufor użytkownika, byłby lepszym dopasowaniem - oczywiście konstrukcja / zniszczenie ostream / streambuf zwiększa wydajność.
MGH,

35

Aktualizacja, sierpień 2019:

Wygląda na to, że C ++ 20 będzie mieć std::format. Implementacja referencyjna to {fmt} . Jeśli teraz szukasz printf()alternatywy, stanie się to nowym „standardowym” podejściem i warto je rozważyć.

Oryginalny:

Użyj Boost.Format . Ma printfskładnię podobną do tej, bezpieczeństwo typów, std::stringwyniki i wiele innych przydatnych rzeczy. Nie wrócisz.


15
... chyba że
martwisz się

Jaki miałoby to wpływ? Zależność Boost byłaby tylko nagłówkiem, bez linkowania, prawda?
Ken Williams

1
@KenWilliams Tak, Boost.Format to tylko nagłówek. Prosty test „witaj świecie” na moim Macu zwiększa się z 10 kB do 78 kB. W rzeczywistym projekcie dodatkowy rozmiar zostanie zamortyzowany w jednostkach kompilacji (daj odpowiednie opcje łącznika), a bezpieczeństwo typu przyniesie inne korzyści.
janm


7

Możesz użyć pliku nagłówkowego iomanip do sformatowania strumienia wyjściowego. Sprawdź to !


Dlaczego ktoś to odrzucił? Czy iomanip nie jest czystym C ++ sposobem na osiągnięcie formatowania w strumieniach? Myślę, że celem jest uniknięcie przechowywania danych w łańcuchach w stylu C, co osiąga się za pomocą iomanip.
Dmitri,

7

Oto fajna funkcja dla sprintów w języku c ++. Strumienie mogą stać się brzydkie, jeśli używasz ich zbyt intensywnie.

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;
    }
}

W C ++ 11 i nowszych wersjach std :: string gwarantuje użycie ciągłego magazynu, który kończy się na '\0', więc dozwolone jest rzutowanie go na char *using &str[0].

Zwrócono uwagę, że argumenty wariadyczne nie powinny następować po przekazaniu przez referencję, a c ++ jest dobry w nie kopiowaniu łańcuchów, jeśli nie musi. W takim przypadku to rozwiązuje problem.

std::string string_format(std::string fmt, ...) {

Bardzo fajne rozwiązanie! Dostosowałem go tutaj: stackoverflow.com/a/3742999/15161, aby lepiej pasował do sprintf-usage.
slashmais

10
Jednak nielegalne: (char*) str.c_str()odrzuca const.
MSalters

jest też problem z przepełnieniem bufora
Barney Szabolcs

@MSalters Correct. Jest na to legalny sposób w C ++ 11.
whitequark

@whitequark: Możesz to dodać jako odpowiedź. W przypadku przepełnienia stosu dobre pytanie pozostaje otwarte, aby umożliwić nowe odpowiedzi.
MSalters

1

W zależności od tego, co dokładnie planujesz sprintf(), std::to_string()może być przydatne i bardziej idiomatyczne niż inne opcje:

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

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

Główną zaletą std::to_string()IMHO jest to, że można go łatwo rozszerzyć, aby obsługiwał dodatkowe typy, które sprintf()nawet nie mogą marzyć o ciągnieniu - coś w rodzaju Object.toString()metody Java .


0

Użyj stringstream, aby osiągnąć ten sam efekt. Możesz także dołączyć <cstdio>i nadal używać snprintf.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.