任何人都可以解释在内存流上使用时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=%dn",written);
int fstatus = fflush(file);
fprintf(stderr,"fstatus=%dn",fstatus);
long ftellpos = ftell(file);
fprintf(stderr,"ftellpos=%ldn",ftellpos);
fstatus = fseek(file, 0, SEEK_END);
fprintf(stderr,"fstatus=%dn",fstatus);
ftellpos = ftell(file);
fprintf(stderr,"ftellpos2=%ldn",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/73dfd088936b92375999e4ab737c7ae2ea7d710e1/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
说:
"当前位置由I/O操作隐含更新。可以使用FSEEK(3)明确更新,并使用FTELL(3)确定。"
其他男子页面提到,Ftell可能不必工作对于不是真正文件的东西。但是,我相信他们确实在牢记那里。
刚刚在讨论中的网络上找到了这句话:
ftell()开放组基本规格问题7 doc states'ftell()应返回流的文件位置指示器的当前值。'如果没有中间调用的文件位置指示器将不会更新FFLUSH功能或文件定位功能(FSEEK,FSETPOS或REWIND),或直到缓冲区已满。
因此,看起来RH和SUSE有一些缓冲处理差异。您需要以一种读取文件中正确位置的方式冲洗缓冲区。