С ++ эквивалент sprintf?

85

Я знаю, что std::coutэто эквивалент printf.

Что такое эквивалент C ++ 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 (...)? Вы не можете форматировать данные произвольно, вы должны полагаться на известный тип, когда вы вводите его в поток с помощью <<оператора.
Андон М. Коулман
1
Мне нужно согласиться с @ AndonM.Coleman по этому поводу. На самом деле это не замена sprintf. Это было бы больше похоже, но это Qt.
lpapp 06
как говорит @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 07
Насколько это повлияет? Зависимость Boost будет только для заголовка, без ссылки, правильно?
Кен Уильямс
1
@KenWilliams Да, Boost.Format - это только заголовок. Простой тест «Привет, мир» на моем Mac увеличился с 10 КБ до 78 КБ. В реальном проекте дополнительный размер будет амортизироваться по модулям компиляции (укажите правильные параметры компоновщика), а безопасность типов дает другие преимущества.
janm
18

sprintf отлично работает на C ++.

Стив Роу
источник
5
Я думаю, что OP имел в виду STL, а не C ++.
Жан-Микаэль Селерье,
4
sprintf требует выделения символьного буфера. Я бы хотел что-то вроде метода "append" для "std :: string", который позволяет мне добавлять отформатированные данные и заботиться о выделении за кулисами.
Victor Eijkhout 04
7

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

Винкрис
источник
Почему кто-то проголосовал против этого? Разве iomanip не использует чистый C ++ способ форматирования потоков? Я думаю, что цель здесь - избежать хранения данных в строках 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 *using &str[0].

Было указано, что переменные аргументы не должны следовать за передачей по ссылке, а С ++ хорош в том, что не копирует строки, если в этом нет необходимости. В таком случае это исправляет.

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.

царственность
источник