С ++ еквівалент sprintf?


Відповіді:


70

std::ostringstream

Приклад:

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

Вихід:

name: nemo, age: 1000

3
Я не думаю, що sprintf пише в stdout. Я б видалив заяву про вставку вище.
Раффі Хатчадуріан,

81
Чим це взагалі віддалено схоже sprintf (...)? Ви не можете довільно форматувати дані, вам доведеться покладатися на відомий тип, коли ви подаєте їх у потік за допомогою <<оператора.
Andon M. Coleman

1
Мені потрібно погодитися з @ AndonM.Coleman щодо цього. Це насправді не заміна спринту. Це було б більше так, але це Qt.
lpapp

як каже @vinkris у своїй відповіді, iomanip досягає форматування. Замість друку на stdoit я б сказав "result = out.str ()".
Дмитро

sprintf / snprintf дозволяє форматувати та друкувати користувачеві виділений масив символів, може бути у стеку. У випадку snprintf () це гарантує відсутність перевитрати. Тут ми виділяємо пам'ять кілька разів, і абонент не має прямого доступу до неї. Потрібно перетворити на рядок, щоб отримати вихідні дані. Std :: ostream із користувацьким std :: streambuf, який використовує буфер користувача, був би кращим збігом - звичайно, побудова / знищення ostream / streambuf додає більше ефективності.
MGH

35

Оновлення, серпень 2019:

Схоже, C ++ 20 буде мати std::format. Довідковою реалізацією є {fmt} . Якщо ви зараз шукаєте printf()альтернативу, це стане новим "стандартним" підходом і варто розглянути.

Оригінал:

Використовуйте Boost.Format . Він має printfподібний синтаксис, безпеку типу, std::stringрезультати та безліч інших чудових речей. Ти не повернешся назад.


15
... якщо вас не турбує розмір вашого виконуваного файлу ..: P
pradyunsg

Наскільки це мало б вплив? Залежність Boost була б лише заголовком, без зв’язування, правильно?
Кен Вільямс

1
@KenWilliams Так, Boost.Format - це лише заголовок. Простий тест "привіт, світові" на моєму Mac збільшується з 10 кБ до 78 кБ. У реальному проекті додатковий розмір буде амортизований між модулями компіляції (надайте правильні варіанти компонувальника), а безпека типу приносить інші переваги.
січень

18

sprintf чудово працює в C ++.


5
Я думаю, що OP означав STL, а не C ++.
Jean-Michaël Celerier

4
sprintf вимагає виділення буфера символів. Я хотів би щось на зразок методу "додати" "std :: string", який дозволяє мені додавати відформатовані дані та дбати про розподіл за кадром.
Victor Eijkhout,

7

Ви можете використовувати файл заголовка iomanip для форматування вихідного потоку. Перевірте це !


Чому хтось підтримав це? Хіба iomanip не є способом чистого C ++ для досягнення форматування в потоках? Я думаю, що мета тут - уникнути зберігання даних у рядках у стилі С, що досягається за допомогою iomanip.
Дмитро

7

Ось приємна функція для c ++ sprintf. Потоки можуть стати некрасивими, якщо ви використовуєте їх занадто інтенсивно.

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 і пізніших версіях std :: string гарантовано використовує суміжне сховище, яке закінчується на '\0', тому законно передати його на char *використання&str[0] .

Було зазначено, що варіативні аргументи не повинні слідувати за передачею за посиланням, і c ++ добре не копіює рядки, якщо це не потрібно. У цьому випадку це виправляє.

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

Дуже приємне рішення! Я адаптував його тут: stackoverflow.com/a/3742999/15161 для більш sprintfточного пристосування -usage.
slashmais

10
Однак незаконно: (char*) str.c_str()відкидає const.
MSalters

також існує проблема переповнення буфера
Барні Саболч

@MSalters Правильно. Існує законний спосіб це зробити в C ++ 11.
whitequark

@whitequark: Не соромтеся додавати це як відповідь. У Stack Overflow гарне запитання залишається відкритим, щоб дати нові відповіді.
MSalters

1

Залежно від того, що саме ви плануєте sprintf(), std::to_string()може бути корисним і більш ідіоматичним, ніж інші варіанти:

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 є те, що його можна легко розширити для підтримки додаткових типів, які sprintf()навіть не можуть мріяти про розтягування - на зразок Object.toString()методу Java .


0

Використовуйте струнний потік для досягнення того ж ефекту. Крім того, ви можете включити <cstdio>та все ще використовувати snprintf.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.