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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.