2011-01-24 7 views
11

Можно создать дубликат:
Should I use printf in my C++ code?Printf против станд :: соиЬ

Если я просто хочу, чтобы напечатать string на экране, я могу сделать это с помощью этих двух способов:

printf("abc"); 

std::cout << "abc" << std::endl; 

Дело в том, что в приведенных выше примерах есть преимущество использования printf за std::cout, или, наоборот?

+6

Если вы пишете код на C++, тогда вам, в общем, следует упомянуть идиомы и библиотеки C++. –

+0

Это зависит от того, на каком языке вы пишете свою программу C или C++. Оба эти метода имеют разные языки, поэтому вы не можете сравнивать их напрямую. –

+1

@Paul R. Спасибо за ваш ответ. Итак, не «printf()», а затем считается идиомой C++? –

ответ

1

Эти два примера делают разные вещи. Последний добавит символ новой строки и вывод заподлицо (результат std::endl). std::cout также медленнее. Кроме того, printf и std::cout достигают того же, и вы можете выбрать, какой бы вы ни предпочитали. В качестве предпочтения я бы использовал std::cout в коде C++. Это более читаемо и безопаснее.

См. this article, если вам нужно отформатировать выходной сигнал, используя std::cout.

+0

Спасибо за ваш ответ. Почему «std :: cout», как вы говорите, медленнее? Что означает «медленнее» здесь? Что касается примера? Благодарю. –

+0

@aali Это медленнее, потому что другие ответы подробно объясняют: он делает больше вещей. Это очень зависит от вашего компилятора, но я видел, что более старые версии GCC во всех случаях более чем на 10 раз медленнее. – marcog

+0

С g ++ 4.x, в тестовых ящиках, которые я совершил, ostreams работают так же быстро, как printfs, если вы 'sync_with_stdio (false)'. –

0

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

+0

Спасибо за ваш ответ. Я видел, что «printf()» позволяет форматировать, тоже ли это означает «cout»? –

+0

Что вы имеете в виду, когда говорите: «printf не является безопасным по типу и вообще не является общим. Единственная причина, по которой вы можете отдать предпочтение printf, - это скорость - из памяти, printf во много раз быстрее, чем cout».? Можете ли вы немного рассказать об этом. Благодарю. –

+0

@aali: cout также обеспечивает форматирование вывода. –

26

Хотя cout является собственно ++ способ C, я считаю, что некоторые люди и компании (в том числе Google) продолжают использовать printf в коде C++, потому что это гораздо проще сделать форматированный вывод с printf чем cout.

Вот интересный пример, который я нашел here.

Сравнить:

printf("%-20s %-20s %5s\n" , "Name" , "Surname" , "Id"); 

и

cout << setw(-20) << "Name" << setw(20) << "Surname" << setw(5) << "Id" << endl; 
+3

+1, вы указали одно преимущество printf, поэтому он выглядит как действительный ответ. – CashCow

+3

Пример, показывающий, что меньшая строка кода не всегда означает более читаемую. Версия 'std :: cout' явно указывает, что она делает на каждом шагу. 'printf' имеет криптическую строку форматирования. –

+2

Это правда, но как только вы привыкнете к этому, можно утверждать, что printf проще в использовании. Лично я всегда считал форматирование потока очень неуклюжим. – dandan78

14

printf и связанные с ним друзья функции C. Они работают на C++, но не имеют безопасности типов C++ std::ostreams. Проблемы могут возникать в программах, которые используют функции printf для форматирования вывода на основе пользовательского ввода (или даже ввода из файла). Например:

int main() 
{ 
    char[] a = {'1', '2', '3', '4'}; // a string that isn't 0-terminated 
    int i = 50; 
    printf("%s", a); // will continue printing characters until a 0 is found in memory 
    printf("%s", i); // will attempt to print a string, but this is actually an integer 
} 

C++ имеет гораздо более сильную типобезопасность (и std::string класс), чтобы помочь предотвратить проблемы, как эти.

+1

@ Zac Howland. Спасибо за ваш ответ. Почему эта строка не объявляется выше 0? Разве строки не заканчиваются 0? И что вы подразумеваете под «безопасностью типа»? Благодарю. –

+0

Я не думаю, что это очень актуально при печати строкового литерала. – marcog

+3

@ aali Он определяет массив символов, который просто может быть интерпретирован как строки в C, он не будет автоматически добавлять нулевой байт в конец массива. –

2

На самом деле для вашего конкретного примера вы должны были спросить, что предпочтительнее, puts или cout. printf печатает форматированный текст, но вы просто выводите текст на консоль.

Для общего использования потоки (iostream, из которых cout являются частью) более расширяемы (вы можете распечатывать свои собственные типы с ними) и более универсальны тем, что вы можете генерировать функции для печати для любого типа потока , а не только консоль (или перенаправленный вывод). Вы можете создать общее поведение потока с помощью printf, используя fprintf, которые принимают FILE * как FILE *, часто не являются реальным файлом, но это более сложно.

Потоки являются «типичными», в которых вы перегружаетесь с типом, который вы печатаете. printf не является типичным с использованием эллипсов, поэтому вы можете получить неопределенные результаты, если вы ввели неправильные типы параметров, которые не соответствуют строке формата, но компилятор не будет жаловаться. Вы даже можете получить поведение seg-fault/undefined (но вы можете использовать cout при неправильном использовании), если вы пропустите параметр или пропустите плохой (например, число для% s, и оно все равно относится к нему как к указателю).

printf имеет некоторые преимущества: вы можете шаблон строки формата, а затем повторно использовать эту строку формата для разных данных, даже если эти данные не находятся в структуре, а использование форматирования для одной переменной не «вставляет» этот формат для дальнейшего использования, поскольку вы указываете формат для каждой переменной. printf также известен как потокобезопасный, тогда как cout фактически нет.

boost объединил преимущества каждого из них с их библиотекой форматирования boost ::.

+0

+1 для упоминания boost :: format – GrahamS

+0

+1 «Вы должны были спросить, что предпочтительнее,' puts' или 'cout'_. я googling, чтобы попытаться найти, кто звонит, кто внутри, puts() имеет в нем вызов 'cout'? – LoneXcoder

2

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

Проблема с использованием обоих и их смешением состоит в том, что выходные буферы, используемые printf и cout, не совпадают, поэтому, если вы не запускаете небуферизованный или явно выведенный вывод, вы можете получить поврежденный вывод.

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

У этой проблемы была Java. язык закончил тем, что получил printf.

Википедия хорошо обсуждает этот вопрос в http://en.wikipedia.org/wiki/Printf#C.2B.2B_alternatives_to_sprintf_for_numeric_conversion.

2

printf был заимствован у C и имеет некоторые ограничения. Наиболее распространенным упомянутым ограничением printf является безопасность типов, так как он полагается на программиста, чтобы правильно сопоставить строку формата с аргументами. Второе ограничение, которое снова возникает из среды varargs, заключается в том, что вы не можете расширять поведение с помощью определенных пользователем типов. printf знает, как печатать набор типов, и это все, что вы выберете из него. Тем не менее, для некоторых вещей, для которых он может быть использован, быстрее и проще форматировать строки с printf, чем с потоками C++.

В то время как большинство современных компиляторов могут решать ограничение безопасности типа и, по крайней мере, предоставлять предупреждения (компилятор может анализировать строку формата и проверять аргументы, предоставленные в вызове), второе ограничение не может быть преодолено. Даже в первом случае есть вещи, с которыми компилятор не может реально помочь, так как проверка нулевого завершения - но опять же, та же проблема связана с std::cout, если вы используете его для печати того же массива.

На другом конце, потоки (в том числе std::cout) может быть расширены для обработки пользовательских типов с помощью перегруженных std::ostream& operator<<(std::ostream&, type const &) для любого заданного пользователя определенного типа type. Они сами по себе являются безопасными типами - если вы переходите к типу, который не перегружен operator<<, компилятор будет жаловаться. С другой стороны, они являются более громоздкими для производства форматированного вывода.

Итак, что вы должны использовать? В общем, я предпочитаю использовать потоки, так как перегрузка operator<< для моих собственных типов проста и их можно использовать равномерно со всеми типами.

Смежные вопросы