#c #iostream
#c #iostream
Вопрос:
Я ищу библиотеку, которая работает аналогично iostreams, в том, что она выполняет преобразования и позволяет записывать данные в буферы памяти, файлы и консоль. Однако я хотел бы что-то типобезопасное, как iostream. Существуют ли какие-либо серьезные библиотеки, которые делают это?
Возможность указывать кодировку вывода для вещей была бы плюсом.
Обратите внимание, что меня не интересуют библиотеки, которые просто поддерживают iostreams, потому что они просто еще усложняют то, что делает iostreams, например boost::format
.
Упреждающий ответ на комментарий: Я не хочу использовать cstdio, потому что при использовании этой системы невозможно, чтобы код зависел от местоположения вывода. То есть вам нужно вызвать одну функцию для отправки данных в буферы, и вам нужно вызвать другую функцию для отправки данных в файлы, и еще одну для консоли и т.д.
ПРАВКА2: В ответ на шквал комментариев ниже: Я сыт по горло как iostreams, так и cstdio. Вот более конкретные причины. Я пытался не вдаваться в «разглагольствования» по этому вопросу, но люди продолжают спрашивать меня, не сошел ли я с ума, так что вот мое обоснование.
cstdio
- Не удается корректно обрабатывать символы Юникода
- Не удается записать что-то вроде строки без ручного управления буфером
- Часто требуется поддержка нестандартных расширений (например,
vsnprintf
) для того, чтобы их можно было использовать (РЕДАКТИРОВАТЬ: Хорошо, стандартная библиотека C99, находящаяся в C 11, добавляет большинство / все из них сейчас) - Невозможно изменить местоположение выходных данных без изменения исходного кода (нестандартные расширения, например, в glibc, позволяют обрабатывать указатель на файл как буфер, что делает это… но это все еще просто нестандартное расширение)
- Делает безопасность «забавной» (до такой степени, что в документах по безопасности целые главы посвящены объяснению проблем, например, со строками формата «printf» и тому подобным)
- Не типобезопасно
iostreams
- Медленно
- Слишком сложный для клиента. Если вы используете только то, что поставляется со стандартной библиотекой, это здорово, но попытка расширить что-либо практически невозможна. Я прочитал всю книгу «Стандартные потоки C IOStreams и локали» — единственную, по-видимому, доступную книгу по этой теме — дважды — и я все еще не знаю, что происходит.
Мне нравятся iostreams в концепции, даже использование operator<<
которого некоторым людям, похоже, не нравится, но мне это кажется слишком продуманным. Кому-то не нужно тратить бесчисленные часы на чтение книг, чтобы быть простым клиентом вашей библиотеки. Конечно, если вы добавляете новый источник вывода или что-то в этом роде, я мог бы понять, но …. клиенты должны быть защищены от такой сложности. (Разве библиотека не для этого?)
Это, пожалуй, единственная неприятная вещь в C , которая «просто работает» на других языках программирования, и я не вижу причин усложнять ее.
Комментарии:
1. Причины производительности часто преувеличиваются — на самом деле я обнаружил, что в последних реализациях iostream может превзойти stdio. С другой стороны, я согласен, что iostream не очень хорошо спроектирован, и стоило бы рассмотреть более приятную альтернативу.
2. @Xeo: Вы должны сохранять состояние потока, использовать эти «сторожевые» средства для обработки ошибок, проверять спецификаторы исключений, чтобы определить, следует ли выбрасывать, восстанавливать состояние потока, несмотря ни на что, и т.д. Я не хочу всей этой сложности.
3. 1 Хороший вопрос, и я сомневаюсь, что вы получите хороший ответ. В любом случае, ничего, что даст вам покой.
4. @Matteo из того немногого, что я понимаю, boost.iostreams определяет концепции для стандартных iostreams, чтобы упростить их расширение. но я не думаю, что они исправляют ад форматированного ввода и форматированного вывода.
5. @jeffamaphone: Да. Мне нравится все остальное — именно эта конкретная библиотека мне не нравится. C сложен, потому что он мощный — ПОТРЯСАЮЩИЕ библиотеки, такие как STL, хотя и показывают, что усложнение того стоит. Сложность имеет смысл, когда она приводит к гибкости; но потоковые реализации других языков намного проще, но такие же гибкие. (Честно говоря, потоки C предшествуют практически всем остальным)
Ответ №1:
Библиотека {fmt}: я только что наткнулся на нее в выступлении на YouTube, и она кажется довольно приятной.
Средство форматирования, основанное на {fmt}, было предложено для стандартизации в C 20: P0645. И P0645, и {fmt} используют синтаксис строки формата, подобный Python, который похож на printf
‘s, но использует {}
в качестве разделителей вместо %
.
Например
#include <fmt/core.h>
int main() {
fmt::print("The answer is {}.", 42);
}
выводит «Ответ 42». на stdout
.
std::format
Функция, предложенная для C 20:
#include <format>
int main() {
std::string s = std::format("The answer is {}.", 42);
}
Примечательные особенности {fmt}:
-
Безопасность типов и памяти с ошибками в строках формата, о которых необязательно сообщается во время компиляции.
-
Расширяемость: пользователи могут писать форматеры для своих типов, включая анализаторы пользовательских спецификаций формата (как в Python).
-
Компактный двоичный код. Приведенный выше пример печати компилируется только:
main: # @main sub rsp, 24 mov qword ptr [rsp], 42 mov rcx, rsp mov edi, offset .L.str mov esi, 17 mov edx, 2 call fmt::v5::vprint(fmt::v5::basic_string_view<char>, fmt::v5::format_args) xor eax, eax add rsp, 24 ret .L.str: .asciz "The answer is {}."
которая сопоставима с
printf
и намного лучше iostreams. -
Производительность: {fmt} значительно выше, чем у обычных реализаций
printf
иiostreams
. Вот результаты теста tinyformat на macOS с clang:================= ============= =========== Library Method Run Time, s ================= ============= =========== libc printf 1.01 libc std::ostream 3.04 {fmt} 1632f72 fmt::print 0.86 tinyformat 2.0.1 tfm::printf 3.23 Boost Format 1.67 boost::format 7.98 Folly Format folly::format 2.23 ================= ============= ===========
Комментарии:
1. Спасибо за редактирование.. Да, библиотека довольно потрясающая.
2. Да, FMT — идеальное сочетание функций, подобных iostream, и синтаксиса, подобного printf, но, насколько я знаю, у него нет никаких функций для чтения входных данных с консоли.
Ответ №2:
Boost.Spirit.Qi для ввода, Boost.Spirit.Karma для вывода. Может читать из / записывать во все, что может быть представлено в виде диапазона итератора.
Комментарии:
1. Мне нравятся обе эти библиотеки — я не думаю, что они могут быть общей заменой iostream, хотя, потому что 1. у них обеих ужасно плохое время компиляции по сравнению с традиционными библиотеками и 2. удачи в отладке сообщений об ошибках, которые вы получаете в случае синтаксической ошибки. Все еще разумный ответ на мой первоначальный вопрос, так что 1.
2. Потоки были слишком сложными в соответствии с OP, поэтому теперь мы используем Boost Spirit? Теперь у нас есть две проблемы!
3. @John : Насколько я понимаю, OP означал сложный с точки зрения простоты расширения и сложности времени выполнения / накладных расходов. В обоих отношениях Boost.Spirit не имеет себе равных, поэтому я придерживаюсь этого ответа.
Ответ №3:
Возможно, вас заинтересует библиотека быстрого формата. Вы также можете посмотреть сравнение на их веб-сайте с различными другими библиотеками.
Комментарии:
1. Вау .. это выглядит действительно очень круто. Придется поиграть и посмотреть, как с этим обстоят дела
2. к сожалению, веб-сайт, похоже, не работает, и для этого требуется STLPort, который, похоже, не в лучшей форме.
3. Я пока снимаю этот флажок из-за зависимости от STLPort (это помешало мне использовать его в то время) — вероятно, я вернусь и проверю это снова, но сначала я хочу получить больше опыта использования библиотеки. (Хотя отсутствие обслуживания в последнее время не является хорошим признаком)
4. Среди прочих проблем он считается «альфа» и имеет тревожно пустой веб-сайт, заставляющий меня опасаться, что будущее может быть неопределенным. Хороший выбор, хотя.
5. Это не STLPort, это STLSoft (что бы это ни было, и оно, похоже, тоже не в лучшей форме).
Ответ №4:
Как насчет использования библиотеки fmt и библиотеки scn, fmt довольно хорошо обрабатывает выходные данные, а scn может обрабатывать входные данные. Я использовал обе эти библиотеки одновременно, и ее использование намного менее болезненно, чем стандартное (и она читабельна!).
Вы должны попробовать их оба.