Может ли кто-нибудь объяснить «правильную» семантику для ftell() при использовании в потоке памяти.
Учитывая следующую программу:
#include <stdio.h>
#include <stdlib.h>
#include <gnu/libc-version.h>
int main(void)
{
puts (gnu_get_libc_version ());
size_t n_buffer = 1024;
char *buffer = calloc(n_buffer, sizeof(char));
FILE *file = fmemopen(buffer, n_buffer, "w");
/* "ABCD" */
static const char magic_number[] =
{
0x41, 0x42, 0x43, 0x44
};
const size_t written = fwrite(magic_number, 1, 4, file);
fprintf(stderr,"written=%d\n",written);
int fstatus = fflush(file);
fprintf(stderr,"fstatus=%d\n",fstatus);
long ftellpos = ftell(file);
fprintf(stderr,"ftellpos=%ld\n",ftellpos);
fstatus = fseek(file, 0, SEEK_END);
fprintf(stderr,"fstatus=%d\n",fstatus);
ftellpos = ftell(file);
fprintf(stderr,"ftellpos2=%ld\n",ftellpos);
return 0;
}
Вывод на RHEL7:
2.17
written=4
fstatus=0
ftellpos=4
fstatus=0
ftellpos2=4
Принимая во внимание, что вывод OpenSUSE Leap 42:
2.22
written=4
fstatus=0
ftellpos=0
fstatus=0
ftellpos2=4
(Это привело к сбою модульного теста в коде, на который я смотрел)
Мои вопросы:
- Требуется ли fseek() (по стандарту), чтобы сделать результат ftell() действительным?
- Это ошибка или изменение в поведении glibc?
- Почему это не работает на OpenSUSE?
Наиболее очевидная реализация состоит в том, что индикатор позиции в файле является индексом в буфере памяти, переданном fmemopen. Трудно понять, как это может пойти не так.
Действительно реализация:
https://github.com/bminor/glibc/blob/73dfd088936b9237599e4ab737c7ae2ea7d710e1/libio/fmemopen.c
Имеет c->pos = pos + s; в строке 85.
И, предположительно, ftell() просто возвращает c->pos (окольным путем)
Между версиями 2.17 и 2.22 произошла некоторая реорганизация исходного кода glibc, что, вероятно, объяснило бы это, если бы я мог его распутать. Но это баг или фича?
Я не уверен, что стандарты Posix и C полностью определяют, должен ли ftell работать правильно для потока памяти. Интуитивно трудно понять, почему это не должно быть предписано, поскольку оно должно просто работать.
http://man7.org/linux/man-pages/man3/fmemopen.3.html
Говорит:
«Текущая позиция неявно обновляется операциями ввода-вывода. Она может быть явно обновлена с помощью fseek (3) и определена с помощью ftell (3)».
На других справочных страницах упоминается, что ftell может не работать с вещами, которые на самом деле не являются файлами. Тем не менее, я считаю, что они действительно имеют в виду устройства.
ftell()
возвращаетlong
, аsize_t
требуется"zu"
. - person chux - Reinstate Monica   schedule 15.09.2017