C ++ Streams против ввода-вывода в стиле C? - PullRequest
25 голосов
/ 16 марта 2011

Я кодировал некоторый C ++ для небольшого хобби-проекта, когда заметил, что использую операции в стиле C для доступа к IO (printf, fopen и т. Д.).

Считается ли это"плохая практика", чтобы задействовать функции C в проектах C ++?Каковы преимущества использования потоков над доступом к вводу-выводу в стиле C?

Ответы [ 10 ]

39 голосов
/ 16 марта 2011

Это горячая тема.

Некоторые люди предпочитают использовать ввод-вывод C ++, поскольку они безопасны по типу (вы не можете иметь расхождения между типом объекта и типом, указанным в строке формата) и более естественным образом работают с остальной частью C ++. способ кодирования.

Однако есть и аргументы для функций C IO (мои личные фавориты). Вот некоторые из них:

  • Они легче интегрируются с локализацией, поскольку вся локализуемая строка не разбивается на более мелкие строки, а в некоторых случаях локализатор может изменить порядок вставленного значения, переместить их в строку, ...
  • Вы можете непосредственно увидеть формат текста, который будет написан (это может быть очень сложно с потоковыми операторами).
  • Поскольку встраивания нет, и только один экземпляр функции printf, сгенерированный код меньше (это может быть важно во встроенной среде).
  • Быстрее, чем функция C ++ в некоторых реализациях.

Лично я не считаю плохой практикой использование C-потока в C ++-коде. Некоторые организации даже рекомендуют использовать их в потоке C ++. То, что я считаю плохим стилем - это использовать оба в одном проекте Думаю, здесь важна последовательность.


Как уже отмечалось, в относительно большом проекте вы, вероятно, не будете использовать их напрямую, но вы будете использовать набор функций-оболочек (или классов), которые лучше всего соответствуют вашему стандарту кодирования и вашим потребностям (локализация, типа безопасность, ...). Вы можете использовать тот или иной интерфейс ввода-вывода для реализации этого интерфейса более высокого уровня, но, вероятно, вы будете использовать только один.


Редактирование: добавление некоторой информации о преимуществах семейства функций форматирования printf, связанных с локализацией. Обратите внимание, что эта информация действительна только для некоторых реализаций.

Вы можете использовать %m$ вместо % для ссылки на параметр по индексу вместо последовательной ссылки на них. Это может быть использовано для изменения порядка значений в отформатированной строке. Следующая программа напишет Hello World! на стандартный вывод.

#include <stdio.h>
int main() {
    printf("%2$s %1$s\n", "World!", "Hello");
    return 0;
}

Рассмотрите возможность перевода этого кода на C ++:

if (nb_files_deleted == 1)
    stream << "One file ";
else
    stream << nb_file_deleted << " files ";
stream << removed from directory \"" << directory << "\"\n";

Это может быть очень сложно. С printf (и библиотекой типа gettext для обработки локализации) код не смешивается со строкой. Таким образом, мы можем передать строку команде по локализации, и нам не придется обновлять код, если на каком-то языке есть особый случай (на каком-то языке, если число объектов равно 0, вы используете форму множественного числа, на другом языке, Есть три формы, одна для единственного числа, одна, когда есть два объекта и форма множественного числа, ...).

printf (ngettext ("One file removed from directory \"%2$s\"",
                  "%1$d files removed from directory \"%2$s\"",
                  n),
        n, dir);
8 голосов
/ 16 марта 2011

printf и друзья ужасно небезопасны по сравнению с <iostream> и не могут быть расширены, плюс, конечно, fopen, и у друзей нет RAII, что означает, что если вы не доказали с помощью профилировщика, что вам определенно нужен разница в производительности (которую вы доказали, существует на вашей платформе и в вашем коде), вы должны быть идиотом до printf.

Редактировать: Локализация это интересная вещь, которую я не учел. Я никогда не локализировал код и не могу прокомментировать относительные возможности локализации printf и <iostream>

6 голосов
/ 16 марта 2011

Для небольшого хобби-проекта я бы, вероятно, выбрал более безопасные для типов потоки C ++ io.

Достаточно забавно, я никогда не видел нетривиального реального проекта, использующего любой из них.Во всех случаях мы использовали некоторые абстракции, построенные поверх встроенного API OS для ввода-вывода.

5 голосов
/ 16 марта 2011

Преимущества

  • Безопасность типов: типы аргументов потоковых операций C ++ проверяются во время компиляции, тогда как printf аргументы передаются через ..., вызывая неопределенное поведение, еслиони не соответствуют форматированию.
  • Управление ресурсами: объекты потока C ++ имеют деструкторы для закрытия файловых дескрипторов, свободных буферов и всего, что у вас есть.Потоки C требуют, чтобы вы не забывали вызывать fclose.

Недостатки

  • Производительность: это, конечно, зависит от реализации, но янашлось, что форматирование с потоками C ++ значительно медленнее, чем эквивалентное printf форматирование.
5 голосов
/ 16 марта 2011

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

4 голосов
/ 16 марта 2011

ИМХО, настоящий программист на C ++ пытается делать что-то идиоматическое C ++; преобразованный в C программист пытается цепляться за старые способы ведения дел. Это связано с удобочитаемостью и согласованностью.

3 голосов
/ 31 декабря 2012

Считается ли "плохой практикой" использование функций C в проектах C ++?

Нет. Функции C часто используются в проектах C ++. Что касается потоков, то Google C ++ Style Guide , например, рекомендует использовать их только в ограниченных случаях, таких как "специальные, локальные, удобочитаемые и ориентированные на других разработчиков, а не на конечных пользователей".

Каковы преимущества использования потоков по сравнению с доступом к вводу-выводу в стиле C?

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

3 голосов
/ 16 марта 2011

Как правило, вы должны предпочитать операторы C ++, они:

- Тип сейфа. Вы не рискуете передать двойной, где формат требует инт.

- Расширяемый. Вы можете написать свои собственные вставки и извлекайте и используйте их.

- Расширяемый. Вы можете определить свои собственные манипуляторы (с приложение специфическое логическое значение), и использовать их. если ты хочу изменить формат всего WidgitNumber (внутренне, int) в вашем выводе, вы меняете манипулятор; вам не нужно найти все в формате операторы, где% d - это WidgitNumber.

- Расширяемый. Вы можете написать свои собственные стоки и источники, и они могут пересылать на другие приемники и источники, фильтруя или расширение ввода или вывода по желанию.

(FWIW: я не думаю, что когда-либо писал приложение, которое не использовал пользовательские >> и << операторы, пользовательские манипуляторы и пользовательские потоковые буферы.) </p>

3 голосов
/ 16 марта 2011

Считается ли "плохой практикой" использование функций C в проектах C ++?

Обычно код ввода-вывода файла должен быть инкапсулирован в реализацию класса или функции. Я бы не стал считать, что любой выбор, который вы делаете в инкапсулированных реализациях, является «плохой практикой», я оставляю за этим термином то, что влияет на пользователя вашей библиотеки или кода (то есть интерфейса). Если вы представляете свой механизм файлового ввода-вывода в интерфейсе, то, IMO, плохая практика, используете ли вы поток ввода-вывода или функции ввода-вывода в стиле C.

Я бы скорее сказал, что функции ввода-вывода в стиле C (вероятно, всегда) являются худшим выбором.

Каковы преимущества использования потоков перед доступом к вводу-выводу в стиле C?

Во-первых, они лучше интегрируются со стандартными конструкциями C ++, такими как std::string. Они довольно хорошо интегрируются с STL <algorithms>. И они позволяют вам создавать инкапсулированные пользовательские операторы чтения / записи (<< и >>) таким образом, чтобы ваши пользовательские классы выглядели почти как примитивные типы при выполнении операций ввода-вывода.

Наконец, потоки ввода-вывода в C ++ могут использовать механизм исключений для сообщения об ошибках в потоке или операциях чтения / записи. Это делает код ввода-вывода файлов намного приятнее, поскольку позволяет избежать ужасного вида механизмов кода ошибок (последовательности операторов if и некрасивых циклов while, которые проверяют код ошибки после каждой операции).

3 голосов
/ 16 марта 2011

Во-первых, вам не нужно сначала преобразовывать объекты C ++ (особенно string s) в C-совместимые формы.

...