Должен ли я использовать printf в моем коде C ++? - PullRequest
67 голосов
/ 07 января 2010

Я обычно использую cout и cerr для записи текста на консоль. Однако иногда мне проще использовать старый добрый оператор printf. Я использую его, когда мне нужно отформатировать вывод.

Один из примеров, где я бы использовал это:

// Lets assume that I'm printing coordinates... 
printf("(%d,%d)\n", x, y);

// To do the same thing as above using cout....
cout << "(" << x << "," << y << ")" << endl;

Я знаю, что могу отформатировать вывод, используя cout, но я уже знаю, как использовать printf. Есть ли причина, по которой я не должен использовать оператор printf?

Ответы [ 19 ]

3 голосов
/ 07 января 2010

Я часто "возвращаюсь" к использованию printf(), но чаще snprintf() для облегчения форматированного вывода. При программировании на C ++ я использую эту обертку, которую я написал некоторое время назад, и называю так (используйте ваш пример, как указано выше): cout << format("(%d,%d)\n", x, y);

Вот заголовок (stdiomm.h):

#pragma once

#include <cstdarg>
#include <string>

template <typename T>
std::basic_string<T> format(T const *format, ...);

template <typename T>
std::basic_string<T> vformat(T const *format, va_list args);

И источник (stdiomm.cpp):

#include "stdiomm.h"
#include <boost/scoped_array.hpp>
#include <cstdio>

template <>
std::wstring vformat(wchar_t const *format, va_list arguments)
{
#if defined(_WIN32)
    int required(_vscwprintf(format, arguments));
    assert(required >= 0);
    boost::scoped_array<wchar_t> buffer(new wchar_t[required + 1]);
    int written(vswprintf(buffer.get(), required + 1, format, arguments));
    assert(written == required);
    return std::wstring(buffer.get(), written);
#else
#   error "No implementation yet"
#endif
}

template <>
std::string vformat(char const *format, va_list arguments)
{
#if defined(_WIN32)
    int required(_vscprintf(format, arguments));
    assert(required >= 0);
    boost::scoped_array<char> buffer(new char[required + 1]);
    int written(vsnprintf(buffer.get(), required + 1, format, arguments));
    assert(written == required);
    return std::string(buffer.get(), written);
#else
    char *buffer;
    int printed = vasprintf(&buffer, format, arguments);
    assert(printed != -1);
    std::string retval(buffer, printed);
    free(buffer);
    return retval;      
#endif
}

template <typename T>
std::basic_string<T> format(T const *format, ...)
{
    va_list ap;
    va_start(ap, format);
    std::basic_string<T> retval(vformat(format, ap));
    va_end(ap);
    return retval;
}

template std::wstring format(wchar_t const *format, ...);
template std::string format(char const *format, ...);

Обновление

После прочтения некоторых других ответов мне, возможно, придется переключиться на boost::format() себя!

3 голосов
/ 07 января 2010

Мне не нравится printf. Отсутствие безопасности типов делает его опасным для использования, плюс необходимость помнить спецификаторы формата - боль. Шаблонные операторы, которые ловко делают правильные вещи, намного лучше. Поэтому я всегда использую потоки C ++ в C ++.

Конечно, многие люди предпочитают printf по другим причинам, перечисленным в другом месте.

1 голос
/ 24 ноября 2017

Вы можете получить лучшее из обоих миров с библиотекой fmt , которая сочетает в себе безопасность и расширяемость iostreams с удобством использования и производительностью (s)printf. Пример:

std::string = fmt::format("The answer is {}", 42);

Библиотека поддерживает синтаксис строки в формате Python-like и printf.

Отказ от ответственности : я являюсь автором библиотеки fmt .

1 голос
/ 29 сентября 2012

Хотя вопрос довольно старый, я хочу добавить свои два цента.

Печать созданных пользователем объектов с помощью printf ()

Это довольно просто, если вы подумаете об этом - вы можете указать свой тип и отправить строку в printf:

std::string to_string(const MyClass &x)
{
     return to_string(x.first)+" "+to_string(x.second);
}

//...

printf("%s is awesome", to_string(my_object).c_str()); //more or less

Жаль, что не было (есть C ++ 11 to_string ()) стандартизированного интерфейса C ++ для строковых объектов ...

printf () ловушка

Один флаг -% n

Единственный выходной параметр - он ожидает указатель на int. Он записывает количество успешно написанных символов в местоположение, указанное этим указателем. Умелое использование может вызвать переполнение, которое является уязвимостью безопасности (см. Строковую атаку в формате printf ()).

0 голосов
/ 26 апреля 2013

Я прочитал предупреждения о том, что cout и cerr небезопасны для многопоточности. Если это правда, это хороший повод избегать их использования. Примечание: я использую GNU g ++ с openMP.

0 голосов
/ 30 января 2012

Это зависит от ситуации. Ничто не идеально. Я использую оба. Потоки хороши для пользовательских типов, так как вы можете перегрузить оператор >> в ostream. Но когда дело доходит до пробелов и т. Д., Лучше использовать printf (). stringstream и тому подобное лучше, чем strcat () в стиле C. Так что используйте тот, который подходит для ситуации.

0 голосов
/ 03 декабря 2011

C ++ потоки переоценены, ведь на самом деле это просто классы с перегруженным оператором <<.
Я много раз читал, что потоки - это C ++ , так как printf - это C , но обе они являются библиотечными функциями, доступными в C ++, поэтому вы должны использовать то, что подходит лучше всего.
Я в основном предпочитаю printf, но я также использовал потоки, которые предоставляют более чистый код и не позволяют вам сопоставлять% заполнителей с аргументами.

0 голосов
/ 07 января 2010

потоки предпочтительны в cpp, поскольку они придерживаются объектно-ориентированной парадигмы cpp, кроме того, что безопасный тип.

printf, с другой стороны, более функциональный подход.

Единственная причина не использовать printf в коде cpp, о которой я могу думать, это не объектно-ориентированная.

это скорее личный выбор.

0 голосов
/ 07 января 2010

Я почти всегда использую printf для временных операторов отладки. Для более постоянного кода я предпочитаю потоки 'c', поскольку они C ++ Way . Хотя boost :: format выглядит многообещающе и может заменить использование моего потока (особенно для сложных форматированных выводов), вероятно, ничто не заменит мне printf в течение длительного времени.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...