.TH LIBMPUIO 3 "Сентябрь 2026" "libmpuio" "Руководство программиста LIBMPUIO" .SH ИМЯ libmpuio \- ввод-вывод в стиле stdio с UCS-2/UTF-8 для чисел LIBMPU произвольной точности .SH БИБЛИОТЕКА Сопутствующая библиотека LIBMPUIO для LIBMPU. .SH ОБЗОР .nf .B #include .PP .B extern mpu_FILE *mpu_stdin; .B extern mpu_FILE *mpu_stdout; .B extern mpu_FILE *mpu_stderr; .fi .SH ОПИСАНИЕ LIBMPUIO предоставляет потоковый интерфейс в стиле stdio без использования объектов libc .BR FILE . Её публичный тип потока \- .BR mpu_FILE , а потоки реальных файлов работают поверх POSIX-дескрипторов. .PP Публичные символьные и строковые интерфейсы используют скалярные typedef LIBMPU .BR __mpu_char8_t , .BR __mpu_char16_t , .B __mpu_char32_t и .BR __mpu_size_t , доступные через .BR . Текст внутри I/O API представлен строгим UCS-2 в .BR __mpu_char16_t . Текст реального файла преобразуется в UTF-8 или из UTF-8 на границе потока. Суррогаты и скалярные значения UTF-8 выше U+FFFF отвергаются с .BR EILSEQ . Сырые операции .BR mpu_fread (3) и .BR mpu_fwrite (3) работают с байтами и не выполняют преобразование текста. .PP Форматированный I/O целых, вещественных и комплексных чисел MPU поддерживает настроенные размеры до .B MPU_REAL_IO_LIMIT (в настоящее время до 65536 бит). Форматированный I/O не ограничивается .BR MPU_MATH_FN_LIMIT . .SH МОДЕЛЬ ТИПОВ ФОРМАТИРОВАННОГО I/O Форматированный I/O намеренно различает обычные объекты C и объекты libmpu. Обычные преобразования, например .B %d или .BR %g , следуют стандартным вариадическим правилам C и извлекают значения типов, определяемых преобразованием и стандартными модификаторами длины. Малые целые аргументы подвергаются обычным преобразованиям аргументов по умолчанию. .PP Преобразования libmpu используют исторический модификатор размера .B z или .BR Z . Обе формы эквивалентны, а строчная .B z зарезервирована LIBMPUIO именно для этой цели; стандартный модификатор длины C .B z для .B size_t не реализован. Если после модификатора размера нет цифр, предполагается 128 бит. Набор модификаторов размера, присутствующих в конкретной сборке, компилируется непосредственно по значению .B MPU_REAL_IO_LIMIT из .BR . Аргумент представляет собой хранилище, адресуемое через указатель, а .I bits задаёт точный размер объекта MPU. Публичные typedef libmpu для чисел произвольной точности являются массивами байтов, поэтому имя объекта естественно преобразуется в указатель при передаче аргументом функции. .PP Вариадический .B va_list не содержит универсальных метаданных типа/размера времени выполнения. Поэтому LIBMPUIO не пытается определить размер объекта MPU по его адресу: явный модификатор .B z/Z является контрактом типа форматированного I/O. Обычные объекты C должны использовать обычные преобразования C; преобразования MPU обычно следует применять к объектам libmpu соответствующего настроенного размера. Примеры и подробные правила аргументов см. в .BR mpu_printf (3) и .BR mpu_scanf (3). .SH ЛОКАЛЬ И ОБЫЧНЫЙ ВВОД-ВЫВОД ВЕЩЕСТВЕННЫХ ЧИСЕЛ Обычные вещественные преобразования C .B %e/%E/%f/%F/%g/%G следуют активному соглашению о десятичном разделителе .BR LC_NUMERIC . При выводе используется formatter libc хост-системы, после чего полученное многобайтовое поле текущей локали декодируется в строгий UCS-2 вместо простого расширения отдельных байтов вывода. При обычном scanf токенизатор получает строку десятичного разделителя локали через .BR localeconv (3), распознаёт соответствующую последовательность UCS-2 во входе и передаёт соответствующий многобайтовый токен локали функции .BR strtold (3). Это делает обычное поведение printf/scanf для вещественных чисел симметричным в локалях, где десятичный разделитель отличается от .BR . . .PP Строчная .B %a зарезервирована LIBMPUIO для многобайтовых строк текущей локали. Вещественные и комплексные преобразования MPU по-прежнему подчиняются грамматике форматированных чисел LIBMPU, а не обычному floating-tokenizer libc. .SH МОДЕЛЬ ПОТОКА Поток содержит состояние буферизации, индикаторы EOF/ошибки, состояние pushback, рекурсивный mutex потока и таблицу переходов backend. LIBMPUIO намеренно имеет три независимых backend: файлы на основе дескрипторов с внешним текстом UTF-8, нативные строковые/памятные потоки UCS-2 и произвольные байтовые callback-потоки, открываемые mpu_fopencookie(3). Все три используют одни и те же механизмы форматирования через более низкоуровневую внутреннюю абстракцию FILE_plus/jump-table. .PP Для реальных текстовых файлов логические позиции являются внешними байтовыми смещениями UTF-8. Упреждающее чтение в буфер и pushback UCS-2 учитываются функцией .BR mpu_ftello (3). .SH МОДЕЛЬ БЛОКИРОВОК Обычные потоковые функции захватывают рекурсивный mutex потока. Функции, имена которых заканчиваются на .BR _unlocked , этого не делают. Unlocked-формы предназначены для участка, уже защищённого .BR mpu_flockfile (3), либо для кода, который иным способом гарантирует эксклюзивный доступ к потоку. .PP Различие unlocked меняет только блокировку. Буферизация, проверка, преобразование UTF-8/UCS-2, возвращаемые значения, индикаторы ошибок и поведение backend в остальном совпадают с соответствующей блокируемой операцией. .PP Глобальный список потоков, используемый .BR mpu_fflush(NULL) и .BR mpu_flushlbf(), защищается только на время построения стабильного snapshot. Потоки в snapshot несут внутренние ссылки жизненного цикла, поэтому блокировка глобального списка освобождается до захвата mutex отдельного потока или входа в код backend. Закрытие сначала удаляет поток из будущих snapshot и откладывает уничтожение объекта, пока более ранний snapshot всё ещё удерживает ссылку. Код приложения всё равно обязан синхронизировать явное закрытие с произвольным обычным параллельным использованием того же указателя на поток. .SH ГРУППЫ ФУНКЦИЙ .TP .B Создание и жизненный цикл потока .BR mpu_fopen (3), .BR mpu_fdopen (3), .BR mpu_freopen (3), .BR mpu_tmpfile (3), .BR mpu_popen (3), .BR mpu_pclose (3), .BR mpu_fopencookie (3), .BR mpu_fclose (3), .BR mpu_fflush (3), .BR mpu_flushlbf (3), .BR mpu_fpurge (3), .BR mpu_fileno (3). .TP .B Потоки памяти UCS-2 .BR mpu_fmemopen (3), .BR mpu_open_memstream (3). .TP .B Диагностика .BR mpu_perror (3), .BR mpu_strerror_r (3). .TP .B Сырой двоичный I/O .BR mpu_fread (3), .BR mpu_fwrite (3) и unlocked-варианты. .TP .B Ввод-вывод символов и строк UCS-2 .BR mpu_fgetc (3), .BR mpu_getc (3), .BR mpu_getchar (3), .BR mpu_ungetc (3), .BR mpu_fputc (3), .BR mpu_putc (3), .BR mpu_putchar (3), .BR mpu_fgets (3), .BR mpu_fputs (3), .BR mpu_puts (3). .TP .B Форматированный вывод .BR mpu_printf (3), .BR mpu_fprintf (3), .BR mpu_sprintf (3), .BR mpu_snprintf (3), .BR mpu_asprintf (3), .BR mpu_dprintf (3) и формы va_list/unlocked. .TP .B Форматированный ввод .BR mpu_scanf (3), .BR mpu_fscanf (3), .BR mpu_sscanf (3) и формы va_list/unlocked. .TP .B Позиционирование .BR mpu_fseek (3), .BR mpu_fseeko (3), .BR mpu_ftell (3), .BR mpu_ftello (3), .BR mpu_fgetpos (3), .BR mpu_fsetpos (3), .BR mpu_rewind (3). .TP .B Буферизация, индикаторы и явная блокировка .BR mpu_setvbuf (3), .BR mpu_setbuf (3), .BR mpu_feof (3), .BR mpu_ferror (3), .BR mpu_clearerr (3), .BR mpu_fpurge (3), .BR mpu_flockfile (3), .BR mpu_ftrylockfile (3), .BR mpu_funlockfile (3). .SH ВОЗВРАЩАЕМЫЕ ЗНАЧЕНИЯ И ОШИБКИ Каждое семейство следует соглашениям возврата в стиле stdio, описанным на его странице руководства. Ошибки системных вызовов сохраняют полезные значения .BR errno . Ошибки потока устанавливают индикатор ошибки; конец ввода устанавливает EOF только когда фактически обнаружено условие конца файла. .SH ПРИМЕЧАНИЯ LIBMPUIO является сопутствующей библиотекой LIBMPU, а не ABI-заменой libc stdio. Не выполняйте приведение между .B mpu_FILE * и libc .BR FILE * . .SH УСИЛЕНИЕ МОДЕЛИ СОСТОЯНИЯ ПОТОКА Все три нативных backend участвуют в единой модели активного состояния READING/WRITING. В частности, потоки памяти UCS-2 устанавливают состояние WRITING при текстовом выводе, что позволяет mpu_fflush(NULL) публиковать активный mpu_open_memstream() так же, как соответствующий явный flush потока. .PP Обычные mpu_puts(), mpu_rewind() и mpu_fileno() удерживают mutex потока на всю логическую операцию; их явно unlocked-аналоги, где они предусмотрены, остаются операциями, синхронизацию которых обеспечивает вызывающая сторона. Командные потоки нельзя передавать mpu_freopen(), и они сохраняют обязательный жизненный цикл через mpu_pclose(). .PP Создание потока напрямую распространяет ошибки инициализации рекурсивного mutex, а стандартный поток, mutex которого не удалось инициализировать, не добавляется в глобальный список потоков. Замена буфера файла и cookie также очищает указатели направления до того, как ошибка выделения памяти могла бы открыть устаревшие адреса. .SH УСИЛЕНИЕ ЖИЗНЕННОГО ЦИКЛА СПИСКА ПОТОКОВ Обход всех потоков использует snapshot с удержанием ссылок вместо удержания mutex глобального списка во время операций backend. Это сохраняет живыми потоки дескрипторов, строк и cookie на протяжении обработки каждого элемента, одновременно убирая блокировку глобального списка из пользовательских callback cookie. .PP Если mpu_fclose() встречает поток, который всё ещё присутствует в более раннем snapshot, функция удаляет этот поток из живого списка и завершает shutdown backend, но откладывает уничтожение объекта FILE и рекурсивного mutex до освобождения последней ссылки snapshot. Более поздний snapshot не может получить новую ссылку на уже удалённый из списка поток. .PP Приватные потоки UCS-2, создаваемые внутри для движков sprintf/snprintf и sscanf, не являются членами публичного глобального списка потоков. Публичные mpu_fmemopen() и mpu_open_memstream() остаются зарегистрированными и потому продолжают участвовать в mpu_fflush(NULL) и mpu_flushlbf(), когда это применимо. .SH УСИЛЕНИЕ БЕЗОПАСНОСТИ ПАМЯТИ И СОСТОЯНИЯ БУФЕРА Замена setvbuf для descriptor- и cookie-потоков транзакционна относительно ошибки выделения памяти: новое хранилище подготавливается заранее, поэтому неудачное выделение не разрушает прежнее пригодное состояние буфера. Неиспользуемый внутренний cache _offset был удалён; логические позиции по-прежнему выводятся из позиции backend вместе с состоянием буферизованного чтения/записи и pushback UCS-2. .PP Makefile в корне проекта собирает только production shared library. Обычные регрессионные тесты независимо собираются в tests/, а stress-наборы AddressSanitizer, UndefinedBehaviorSanitizer и ThreadSanitizer \- независимо в tests/asan, tests/ubsan и tests/tsan. Каждый каталог тестов собирает собственную локальную libmpuio.so и запускает программы с LD_LIBRARY_PATH=. Поэтому инструментирование sanitizer никогда не требует изменения или пересборки production-объектов в другом режиме. .SH СМ. ТАКЖЕ .BR mpu_fopen (3), .BR mpu_fmemopen (3), .BR mpu_fopencookie (3), .BR mpu_fpurge (3), .BR mpu_perror (3), .BR mpu_fgetc (3), .BR mpu_fread (3), .BR mpu_fseek (3), .BR mpu_printf (3), .BR mpu_scanf (3), .BR mpu_flockfile (3), .BR mpu_unlocked (3) .SH ВИДИМОСТЬ ВНУТРЕННИХ СИМВОЛОВ Внутренние межмодульные объявления в приватных заголовках LIBMPUIO являются обычными объявлениями Bextern P. Вспомогательные макросы внутренних символов определены в Bmpu-symbols.h P. В C-файле, определяющем каждую приватную межмодульную функцию или объект данных, после определения используется B__mpu_hidden_decl(name) P. Макрос применяет GCC-атрибут Bvisibility("hidden") P только когда одновременно определены BSHARED P и BHAVE_HIDDEN_VISIBILITY_ATTRIBUTE P; последний предоставляется через Bconfig.h P. Таким образом, политика возможностей компилятора не попадает в приватные объявления интерфейса. Вспомогательные функции уровня файла остаются Bstatic P. .PP Это правило также охватывает приватные jump-table и состояние списка потоков: B__mpu_IO_file_jumps P, B__mpu_IO_str_jumps P, B__mpu_IO_list_all P и B__mpu_IO_list_lock P. Поэтому shared library не экспортирует ни одного символа с приватным префиксом B__mpu_ P. .PP Hidden-объявления определяют только границу ABI; документированные публичные функции Bmpu_* P и публичные объекты потоков остаются экспортируемыми.