С ++ еквівалент 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.