Итак, я копался в том, как реализована часть stdio libc, и я столкнулся с другим вопросом. Глядя на man setvbuf
я вижу следующее:
Когда над файлом происходит первая операция ввода-вывода, вызывается malloc(3) и создается буфер.
Это имеет смысл, ваша программа не должна иметь malloc
для ввода-вывода, если только вы ее не используете. Моя интуиция на это такова, что libc сама наведет здесь свой беспорядок. Я могу только предположить, что это так, потому что valgrind не сообщает об утечках памяти (они, конечно, могут сделать что-то грязное и не выделять ее напрямую через malloc
... но мы предположим, что сейчас он буквально использует malloc
).
Но вы также можете указать свой собственный буфер...
int main() {
char *p = malloc(100);
setvbuf(stdio, p, _IOFBF, 100);
puts("hello world");
}
О нет, утечка памяти! Валгринд подтверждает это. Таким образом, кажется, что всякий раз, когда stdio выделяет буфер самостоятельно, он автоматически удаляется (самое позднее при выходе из программы, но, возможно, при закрытии потока). Но если вы указываете буфер явно, то вы должны очистить его самостоятельно.
Однако есть одна загвоздка. На странице руководства также говорится следующее:
Вы должны убедиться, что пространство, на которое указывает buf, все еще существует к временному потоку, что также происходит при завершении программы. Например, следующее неверно:
Теперь это становится интересным для стандартных потоков. Как правильно очистить для них выделенный вручную буфер, поскольку они закрываются при завершении программы? Я мог бы представить себе «очистить это, когда я закрою флаг» внутри файловой структуры, но это становится волосатым, потому что, если я правильно прочитаю это, сделаю что-то вроде этого:
setvbuf(stdout, 0, _IOFBF, 0);
printf("hello ");
setvbuf(stdout, 0, _IOLBF, 0);
printf("world\n");
вызовет 2 выделения памяти стандартной библиотекой из-за этого предложения:
Если аргумент buf равен NULL, затрагивается только режим; новый буфер будет выделен при следующей операции чтения или записи.
EDIT: дополнение к моему вопросу. Поскольку ясно, что я должен free
передать любые буферы в setvbuf
, если я действительно использую его на stdout
, есть ли какой-нибудь практический способ free
его? Он должен жить до конца программы. Лучшее, что я могу придумать, это fclose(stdout)
затем освободить его или использовать статический буфер, как упоминали некоторые люди. Я спрашиваю, потому что это кажется неуклюжим дизайнерским решением.