В последнее время я наткнулся на сообщение: How to read an entire file into memory in C++, где описаны различные методы чтения файлов. Каждый подход прокомментирует его эффективность или риски, связанные с неопределенным поведением . Среди списка следующий пример представлен:Чтение файлов и неопределенное поведение
// Bad code; undefined behaviour
in.seekg(0, std::ios_base::end);
Которые в основном в той или подобной форме часто используется на самом деле читать размер файла. Рассуждение представлены в посте, в общем, то, что в C standard (N1570) §7.21.3
говорится, что:
Установка индикатора позиции файла конца-файла, как с FSEEK (файл, 0, SEEK_END), имеет неопределенное поведение для двоичного потока (из-за возможных завершающих нулевых символов) или для любого потока с зависящим от состояния кодированием, которое не обязательно заканчивается в начальном состоянии сдвига.
Что footnote 268
для:
Файл не должен начинаться, ни заканчиваться в начальном состоянии сдвига
Для подтверждения выше для C++ 11 есть дополнительная ссылка C++ standard draft (N3242) 27.9.1.1
, в котором говорится:
Ограничения на чтение и запись последовательности, контролируемой Объект класса basic_filebuf те же, что и для чтения и записи со стандартными файлами F библиотеки.
Где basic_filebuf
согласно cppreference является частью реализации для basic_ifstream
(внутреннего буфера). Что указывает на то, что реализация ifstream
должна быть также обременена обозначенным поведением.
Из того, что я понял из описания и из того, что мне удалось выкопать, эта проблема в основном связана с широко ориентированными потоками, которые могут не заканчиваться в initial shift state
.
Кажется, это не может быть типичным случаем из-за популярного использования для расчета размера файла. Тем не менее тема для меня не совсем понятна. Таким образом, следующие вопросы :
- Что на самом деле
initial state shift
? Я предполагаю, что это не может быть связано с кластерами данных. Больше для многобайтовой кодировки символов, но таким образом проблема не ограничивалась бы только не двоичными потоками? - Когда мы имеем дело с
wide-
иnarrow-oriented
потоками? Я знаю, что:"A newly opened stream has no orientation."
и ориентация определяется при первом вызове ввода-вывода в потоке. Но на практике есть, скажем, любые значения по умолчанию, зависящие от типа потока, системы, локали или чего-то еще? - Если это еще не ответили или не обозначено, что является практическим примером того, когда такое неопределенное поведение может произойти? В том смысле, что можно воспроизвести его.
Вы правы, я тоже это видел. Это сделало бы приобретенный размер неправильным. Тем не менее вывод заключался в следующем: «Вы можете получить количество символов с ftell() в двоичном режиме ... но вы не можете искать конец файла с помощью fseek (p_file, 0, SEEK_END). Кроме того, некоторые платформы хранить файлы в виде записей фиксированного размера. У вас есть знания, какие платформы особенно? Решение, представленное автором с использованием 'gcount', выглядит действительным. Тем не менее, меня больше интересует, где подход 'seek to to end-to-get-size' может оказаться неудачным на практике. – Dusteh
@ Dusteh Дополнительная информация размещена в ответе. Говоря это, я действительно не знаю, как воспроизвести «доступ к файлам с записью» на обычных доступных мне OS-es. –