Являются ли функции ввода-вывода в формате C (printf, sprintf и т. Д.) Более популярными, чем IOStream, и если да, то почему?

В последнее время я просматривал много кода, созданного другими, и случайно заметил, что все часто используют функции C в стиле "printf", но функции C ++, изученные в школе (в частности, cout), не кажутся такими популярными.

Верно ли это наблюдение и есть ли для этого причина? Соглашение?

Спасибо,

R


person Russel    schedule 29.08.2010    source источник
comment
Everybody кажется несколько крайним заявлением.   -  person Martin York    schedule 29.08.2010
comment
См. Также: stackoverflow.com/questions/119098/   -  person Martin York    schedule 29.08.2010
comment
кто все, и вы не должны делать такие общие предположения.   -  person    schedule 29.08.2010
comment
он совершенно прав. это потому, что iostreams настолько сложен, что заставляет даже программистов на C ++ плакать, а они привыкли гадить :)   -  person Matt Joiner    schedule 29.08.2010
comment
Я использую только iostreams для ввода, вывода или форматирования. У них есть свои причуды, но, по крайней мере, они безопасны по типу.   -  person Matthieu M.    schedule 29.08.2010


Ответы (6)


Лично я использую printf вместо iostream (например, cout), потому что я думаю, что это понятнее.

Когда вы выполняете форматирование с помощью iostream, вам приходится << всякие странности вроде setiosflags и setf. Я никогда не могу вспомнить, в каком пространстве имен находится все это, не говоря уже о том, что все это делает. Даже когда я это делаю, я разочарован тем, насколько многословным и неинтуитивным выглядит код.

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

Еще одним преимуществом является то, что printf не имеет состояния: в отличие от cout, мне не нужно вспоминать, какие функции-члены были вызваны в printf или какие византийские комбинации флагов были << добавлены в него. Это большой плюс для удобочитаемости.

person Andrew Cone    schedule 29.08.2010
comment
+1 за указание на различие между состоянием и безгражданством. действительно приятно, когда вам не нужно беспокоиться о том, будут ли ваши попытки вывода данных наступать друг на друга. - person JustJeff; 29.08.2010
comment
Следует также отметить, что вы можете использовать флаги в стиле printf со строками C ++, используя boost::format - person bdonlan; 29.08.2010

Я думаю, что вкус - одна из возможных причин. Лично я нахожу это:

printf("%8d: %s\n", customer->id, customer->name);

более читабельно, чем это:

std::cout << customer->id << ": " << customer->name << std::endl;

Также есть проблема с локализацией. printf позволяет изменить форматирование в соответствии с другими языками и культурами пользовательского интерфейса, что становится серьезной задачей с iostreams, если вы не используете что-то вроде Boost Format.

person Mhmmd    schedule 29.08.2010
comment
Странный ответ. Поддержка локалей на самом деле является той точкой, в которой iostreams значительно лучше, чем printf и на самом деле не сложнее в использовании. - person Martin Ba; 05.12.2013

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

Лично я использую потоки почти для всего, потому что они позволяют мне записывать функцию в консоль, файл или строку без необходимости изменять функцию.

person Billy ONeal    schedule 29.08.2010
comment
Вы знаете, что вы можете использовать потоки со спецификаторами формата в стиле printf с boost::format :) - person bdonlan; 29.08.2010
comment
Передать FILE* в качестве параметра так же просто, как передать параметр ostream. Разрешение fprintf записи в консоль или файл. - person gwell; 29.08.2010
comment
@gwell: Последний раз я проверял, я не могу записать ФАЙЛ * в буфер памяти. - person Billy ONeal; 29.08.2010
comment
@ Билли Онил, посмотри еще раз, эти штуки существуют! - person Matt Joiner; 29.08.2010
comment
Библиотека GNU поддерживает fmemopen(). Это не стандарт, но может существовать. См. cs.utah.edu/dept /old/texinfo/glibc-manual-0.02/ - person gwell; 29.08.2010
comment
С помощью потоков вы можете, например, написать производную от std::ostream, которая автоматически сжимает данные, или std::istream, которая действует как дешифратор SSL. Это просто более эффективно, чем передача FILE* - person Tomaka17; 29.08.2010
comment
@Gwell: Но для этого нужно знать размер вывода заранее. Это (вообще говоря) нереально. - person Billy ONeal; 29.08.2010

Там, где я работаю, мы используем форматирование в стиле printf. Это потому, что раньше мы интенсивно использовали класс MFC CString и его printf-стиль Format метод. Мы постепенно отказываемся от MFC, но не изменили наш подход к форматированию строк.

Что касается того, какой из них разработан лучше, см. Кто спроектировал / разработал IOStream для C ++ и будет ли он по-прежнему считаться хорошо разработанным по сегодняшним стандартам?

person dan04    schedule 29.08.2010
comment
+1 за хорошую перекрестную ссылку. - person Jonathan Leffler; 29.08.2010

Функции семейств printf и scanf имеют две основные проблемы: безопасность типов и безопасность памяти. Довольно легко сделать несоответствие между строкой спецификации и приведенным ниже списком аргументов переменной длины. Кроме того, переполнение буфера через scanf является классической уязвимостью безопасности. Короче говоря, не используйте их.

Потоки C ++ обеспечивают безопасность типов и памяти, а также расширяемость форматирования. Они намного мощнее и проще в использовании, чем printf и scanf.

Кроме того, как предлагает ShaderOp, библиотека форматов Boost обеспечивает такую ​​же безопасность, но позволяет старым программистам на C чувствовать себя более комфортно.

person smithco    schedule 29.08.2010
comment
C ++ - это достаточно низкий уровень, чтобы вы всегда могли выстрелить себе в ногу, даже с потоками и безопасностью типов - например, cout << *(int *)&foo; С другой стороны, любой достойный компилятор C будет выдавать предупреждения о несовпадении типа printf строки формата, поэтому я не думаю, что «безопасность» - веский аргумент в пользу друг друга. С другой стороны, потоки C ++ имеют по крайней мере 2 основных недостатка по сравнению с printf (особенно printf с расширениями локализации XSI): простота перевода сообщений для целей локализации и отсутствие состояния (потенциально большая проблема с потоками). - person R.. GitHub STOP HELPING ICE; 29.08.2010
comment
Компилятор может проверить вашу строку формата только в том случае, если он знает, что это за строка формата. Но одним из преимуществ printf перед iostreams является то, что вы можете настроить строку формата во время выполнения. Так что безопасность типов, безусловно, кажется мне веским аргументом. - person Dennis Zickefoose; 29.08.2010
comment
@R любой достойный компилятор C ++ поймает приведение в стиле C и также выдаст предупреждение - person Sam Miller; 29.08.2010
comment
@Dennis: любой, кто создает строки форматирования во время выполнения (за исключением загрузки интернационализированной версии), должен быть убит (из-за недостатков безопасности, если ничего другого). - person Billy ONeal; 29.08.2010
comment
@Billy: Загрузка интернационализированной версии - это именно то, о чем я говорил. Компилятор тут не поможет. - person Dennis Zickefoose; 29.08.2010
comment
@Dennis: GCC может справиться с этим с помощью атрибута format_arg. Этот атрибут означает, что функция (например, gettext ()) изменяет строку формата таким образом, что она принимает те же параметры. Кроме того, инструменты gettext могут проверять, используют ли переведенные строки формата те же параметры. - person jilles; 29.08.2010
comment
@Dennis: вам лучше пройти некоторую процедуру проверки, чтобы убедиться, что интернационализированная версия соответствует исходной версии :) - person Matthieu M.; 29.08.2010
comment
@jilles: Значит, printf является типизированным, если вы используете конкретную нестандартную библиотеку с соответствующими этапами предварительной обработки, а ваш компилятор поддерживает определенные нестандартные расширения? Это не особо веский аргумент. Не поймите меня неправильно, я предпочитаю ввод-вывод с C вместо ввода-вывода C ++ для многих вещей, и локализация - одна из них. - person Dennis Zickefoose; 29.08.2010

Я собираюсь предположить, что printf используется более широко, потому что

  • он использовался довольно много лет, прежде чем появились компиляторы и потоки C ++
  • C используется больше, чем C ++
  • много операций ввода-вывода было выполнено для таких вещей, как Windows API, для которого printf естественным образом подходит для Open / Read / Write / Close / и т. д.
person joe snyder    schedule 29.08.2010