#c #linux #fstream #buffered
#c #linux #fstream #буферизованный
Вопрос:
Я пытаюсь записать непосредственно в выходной буфер fstream, чтобы избежать memcpy
.
Почему следующий код не работает?
Он компилирует, запускает и выдает выходной файл нужной длины в Linux. Но выходной файл не содержит правильного текста. Также обратите внимание, что по какой-то причине, когда я комментирую две строки, включающие str2
, создается выходной файл нулевой длины.
Примечание: В этом примере не удается избежать memcpy
, но если это сработает, это поможет мне избежать memcpy
в моем приложении.
#include <fstream>
int main(int argc, char *argv[]) {
std::fstream out;
char buffer[512];
out.rdbuf()->pubsetbuf(buffer, 512);
out.open("file.txt", std::fstream::out);
char *str1 = "test text.";
strcpy(buffer, str1);
out.rdbuf()->pubseekpos(strlen(str1), std::ios_base::out);
char *str2 = "why?";
out << str2;
out.flush();
out.close();
}
Комментарии:
1.
to avoid a memcpy
— извините, но это просто глупо.memcpy
это одна из самых быстрых операций.2. Вы действительно уверены, что стоимость
memcpy
действительно имеет значение по сравнению со стоимостью фактического выполнения ввода-вывода? Вы профилировали его? Это может быть просто преждевременной оптимизацией, и вам следует сосредоточить свои усилия в другом месте.3. Есть несколько комментариев относительно того, «почему» я это делаю. Давайте пока оставим это в стороне. Суть в том, что код не создает выходной файл с текстом: «тестовый текст. почему?» Кто-нибудь может сказать мне, почему?
4. @Xeo: Вы не только раздражаете, отвечая на вопрос, который не был задан, вы также ошибаетесь. Несмотря на то, что memcpy () быстр, его стоимость измерима, и его устранение может дать заметный прирост производительности, например, 10%, который я измерил в написанном мной анализаторе: article.gmane.org/gmane.comp.lang.lua.general/77955
5. @Josh: «отвечая» — я поместил это как комментарий именно потому, что это не ответ.
Ответ №1:
Вы предоставляете потоку буфер для его внутреннего использования. Тогда вы не даете ему ничего для записи.
Тот факт, что вы копируете что-либо в буфер, не сообщая потоку, ничего не дает вам в файле.
Как вы могли заметить, seekpos предназначен для позиционирования в файле, а не для перемещения в буфере. Буфер предназначен только для внутреннего использования потока!
Ответ №2:
При out.rdbuf()->pubseekpos(strlen(str1), std::ios_base::out);
этом потоку предлагается пропустить пересылку через вновь созданный файл. Можете ли вы ожидать, что он будет извлекать данные из указанного вами буфера? Подсказка: видели ли вы какие-либо примеры, включающие указание буфера, в котором говорилось, что вам нужно каким-либо образом инициализировать его или указать начальное количество содержащихся в нем символов, не содержащих мусора? Нет … потому что сам поток отслеживает, какие части буфера используются. Следовательно, когда вы берете предполагаемый пустой буфер и пропускаете вперед, он генерирует промежуточные значения NUL. Для них не имело бы смысла устанавливать их в буфере (поэтому простое выполнение a memcpy
после pubseekpos
также не сработает) — что, если вы перескочили больше, чем размер буфера вперед?
Надеюсь, это послужит хотя бы иллюстрацией проблемы, хотя на данном этапе я не задумывался о том, как вы могли бы заставить поток изменить его «отслеживание» значимого содержимого буфера….
Ответ №3:
Пока еще рано, но разве вы в основном не делаете
#include <fstream>
int main(int argc, char *argv[])
{
std::fstream out;
out.open("file.txt", std::fstream::out);
out << "test text";
out << "why?";
out.flush();
out.close();
}
?
Комментарии:
1. В этом примере, да! Но могу ли я получить прямой доступ (указатель на чтение) к выходному буферу?
2. чего вы хотите этим добиться? поскольку вы не вызываете никакой операции записи, я почти уверен, что некоторая реализация ничего не запишет. вы манипулируете памятью, но не записываете в файл. Что вы на самом деле хотите сделать?
3. @user Нет, но я верю, что вы можете скопировать его в кучу.
Ответ №4:
Я недостаточно знаком с библиотекой C iostream, чтобы сказать, что не так с вашей программой, я бы только упомянул, что если вы хотите выполнить свою собственную буферизацию, вероятно, было бы проще использовать интерфейсы read () и write () напрямую (man 2 write). Если вы выполняете свою собственную буферизацию, библиотеки iostream, вероятно, не принесут вам много пользы и только затуманят то, что происходит на самом деле.
Ответ №5:
Я вижу три возможности
- Реализуйте свой собственный класс stream-buffer
- Используйте собственный файловый API
- Отключите буферизацию с помощью
pubsetbuf(0, 0)
Реализация буфера потока на самом деле не так сложна и даст вам возможность сочетать вставку потока в стиле C с прямым доступом к памяти без ущерба для производительности.