2017-09-14 42 views
3

任何人都可以在内存流中解释ftell()的'正确'语义。在内存流上使用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飞跃器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(以一种迂回的方式)

已经有glibc的源源的一些重新组织2.17和2.22 这可能可以解释之间这个如果我能解开它。 但它是一个错误或功能?

我不确定Posix和C标准是否完全指定fllll 应该对内存流正常工作。 直觉上很难看出为什么它不应该强制执行,因为它 应该只是工作。

​​

说:

“的当前位置由隐式I/O操作更新 可以使用FSEEK明确地更新(3),以及使用FTELL(3)来确定的。”。

其他手册页提到,ftell可能不需要为非真正的文件工作 。 但是,我相信他们真的在那里有设备。

+0

那么,关于**标准函数的唯一权威资源是什么告诉你的? – Olaf

+0

听起来像一个错误 - [文件在这里](https://sourceware.org/bugzilla/enter_bug.cgi?product=glibc) – o11c

+1

尽管不太可能出现这个问题,但在这里完成的随机整数类型转换为帖子添加了不必要的问题。建议使用正确的类型和打印说明符。 'ftell()'返回'long','size_t'需要''zu'''。 – chux

回答

0

刚刚发现在网络上这句话的讨论:

的FTELL()公开组基本规范问题7个DOC国FTELL()应流返回文件位置指示器的当前值。'文件位置指示器不会在没有对fflush函数或文件定位函数(fseek,fsetpos或rewind)的插入调用的情况下更新,或者直到缓冲区已满。

因此,它看起来像rh和suse有一些缓冲区处理差异。您需要刷新缓冲区以读取文件中的正确位置。

+0

我很清楚这一要求。请注意,在我的原始示例中写入后有一个fflush调用。 –

+0

“我在泥土中发现了这个地方”并不是一个好的开始。如果允许或不允许,它不会回答(它是)。 – Olaf

+0

@Olaf是的,我知道,但它指向一个文档并解释行为。 – Serge