Sprintf'in C ++ eşdeğeri?


85

Bunun std::coutC ++ eşdeğeri olduğunu biliyorum printf.

C ++ eşdeğeri sprintfnedir?

Yanıtlar:


70

std::ostringstream

Misal:

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

Çıktı:

name: nemo, age: 1000

3
Sprintf'in stdout'a yazdığını sanmıyorum. Yukarıdaki ekleme ifadesini kaldırırdım.
Raffi Khatchadourian

81
Buna uzaktan nasıl benziyor sprintf (...)? Verileri keyfi olarak biçimlendiremezsiniz, <<operatörü kullanarak akışa beslediğinizde bilinen türe güvenmeniz gerekir .
Andon M. Coleman

1
Bu konuda @ AndonM.Coleman ile aynı fikirde olmam gerekiyor. Bu gerçekten bir sprintf değişimi değil. Bu daha çok buna benzer, ama bu Qt.
lpapp

@ vinkris'in cevabında söylediği gibi, iomanip biçimlendirmeyi başarıyor. Stdoit'e yazdırmak yerine "sonuç = out.str ()" derdim.
Dmitri

sprintf / snprintf, kullanıcı tarafından ayrılmış bir karakter dizisine biçimlendirmeye ve yazdırmaya izin verir, yığın üzerinde olabilir. Snprintf () durumunda taşma olmamasını sağlar. Burada hafızayı birkaç kez ayırıyoruz ve arayanın ona doğrudan erişimi yok. Çıktı almak için bir dizgeye dönüştürmeniz gerekir. Kullanıcı tamponunu alan özel bir std :: streambuf'a sahip bir std :: ostream daha iyi bir eşleşme olacaktır - tabii ki ostream / streambuf'un inşası / yok edilmesi daha fazla verimsizlik sağlar.
MGH

35

Güncelleme, Ağustos 2019:

C ++ 20'ye sahip olacak gibi görünüyor std::format. Referans uygulaması {fmt} . printf()Şimdi bir alternatif arıyorsanız , bu yeni "standart" yaklaşım olacaktır ve dikkate alınmaya değerdir.

Orijinal:

Boost.Format kullanın . It has printfbenzeri sözdizimi, tip güvenlik, std::stringsonuçlar ve diğer şık sürü. Geri dönmeyeceksin.


15
... çalıştırılabilir dosyanın boyutu konusunda endişelenmiyorsanız ..: P
pradyunsg

Bunun ne kadar etkisi olur? Boost bağımlılığı yalnızca başlık olacak, bağlantı yok, doğru mu?
Ken Williams

1
@KenWilliams Evet, Boost.Format yalnızca başlıktır. Mac'imdeki basit bir "merhaba, dünya" testi 10kB'den 78kB'ye çıktı. Gerçek bir projede fazladan boyut, derleme birimlerinde amortismana tabi tutulacaktır (doğru bağlayıcı seçeneklerini verin) ve tür güvenliği başka faydalar da sağlar.
2017

18

sprintf , C ++ 'da gayet iyi çalışır.


5
Bence OP, C ++ yerine STL anlamına geliyordu.
Jean-Michaël Celerier 13

4
sprintf, karakter tamponunu ayırmanızı gerektirir. "Std :: string" nin "append" metodu gibi biçimlendirilmiş verileri eklememe ve perde arkasına ayırmayla ilgilenmeme izin veren bir şey istiyorum.
Victor Eijkhout

7

Çıktı akışını biçimlendirmek için iomanip başlık dosyasını kullanabilirsiniz. Bunu kontrol edin !


Neden birisi buna olumsuz oy verdi? İomanip, akışlarda biçimlendirmeyi sağlamanın saf C ++ yolu değil mi? Buradaki amacın, iomanip ile elde edilen C tarzı dizelerde veri depolamaktan kaçınmak olduğunu düşünüyorum.
Dmitri

7

İşte bir c ++ sprintf için güzel bir işlev. Çok fazla kullanırsanız akışlar çirkinleşebilir.

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

C ++ 11 ve sonraki sürümlerinde, std :: string bitişik depolama kullanmak garanti bununla biter '\0'o için döküm yasal, yani char *kullanarak &str[0].

Varyadik argümanların referans olarak geçişi takip etmemesi gerektiği ve c ++ 'nın gerekli değilse dizeleri kopyalamama konusunda iyi olduğu belirtildi. Bu durumda, bu onu düzeltir.

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

Çok güzel çözüm! Bunu burada uyarladım: stackoverflow.com/a/3742999/15161 , sprintf-usage'a daha yakın olacak şekilde .
slashmais

10
Yasadışı olsa da: (char*) str.c_str()atıyor const.
MSalters

ayrıca gizlenen arabellek taşması sorunu var
Barney Szabolcs

@MSalters Doğru. Bunu C ++ 11'de yapmanın yasal bir yolu var.
whitequark

@whitequark: Bunu bir yanıt olarak eklemekten çekinmeyin. Stack Overflow'da, yeni cevaplara izin vermek için iyi soru açık kalır.
MSalters

1

Tam olarak ne yapmayı planladığınıza bağlı olarak sprintf(), std::to_string()diğer seçeneklerden daha kullanışlı ve daha deyimsel olabilir:

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

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

std::to_string()IMHO'nun temel avantajı , zorlaştırmayı sprintf()hayal bile edemeyen ek türleri desteklemek için kolayca genişletilebilmesidir - Java'nın Object.toString()yöntemi gibi .


0

Aynı efekti elde etmek için bir dizi akışı kullanın. Ayrıca <cstdio>snprintf'i ekleyebilir ve kullanmaya devam edebilirsiniz .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.