首页 文章

FSEEK偏移接受超过它应接受的范围

提问于
浏览
0

Specification:之后

对于文本流,偏移量应为零,或者offset应为先前成功调用与同一文件关联的流上的ftell函数返回的值,并且应为SEEK_SET .

我知道 offset 必须是 ftell 函数的retun值,或者0, whence 必须是 SEET_SET (或0) . 但我使用了一些整数作为偏移和不同的 SEEK_... 它似乎运作良好 .

例如,这些工作:

fseek(file, 4, SEEK_CUR);
fseek(file, -1, SEEK_END);
fseek(file, 0, SEEK_CUR);

当我阅读规范时,在我看来它应该不起作用 . 我试过这种方式多次使用fseek,它从未失败过 . 它为什么有效,我没有得到什么?

5 回答

  • 0

    当我阅读规范时,在我看来它应该不起作用 .

    规范说明了必须工作的内容 . 它应该被视为创建c库的人的最低要求(即 fseek 等人的实现者) .

    使用不正确可能仍然有效,但无法保证 . 结果取决于平台 .

    例如, fseek 的Linux手册页说:

    fseek()函数设置stream指向的流的文件位置指示符 . 以字节为单位测量的新位置是通过将偏移字节添加到由whence指定的位置来获得的 . 如果whence设置为SEEK_SET,SEEK_CUR或SEEK_END,则偏移量分别相对于文件的开头,当前位置指示符或文件结尾 . 成功调用fseek()函数会清除流的文件结束指示符,并撤消ungetc(3)函数对同一流的任何影响 .

    您可以看到,您尝试过的内容将在Linux中用于文本和二进制流 . 但是,可能存在 fseek 不能与SEEK_CUR或SEEK_END一起用于文本流的平台 .

    还要注意,流可以与不同的东西相关联:文件,键盘,套接字,终端窗口,设备等 .

  • 0

    在ftell文档中,您可以阅读

    对于文本流,数值可能没有意义但仍可用于稍后使用fseek将位置恢复到相同位置(如果使用ungetc放回的字符仍未等待读取,则行为未定义) .

    你引用的意思是如果你知道你想把指针放在哪里就可以使用它,你可能知道它,因为在优先级中你调用了ftell() .

    您对fseek的所有调用都是有效的,但在文本文件中使用fseek进行移动没有太大意义,因为它不是随机访问(二进制)文件,但这并不意味着使用它是错误的 .

    对于文本文件,您可以找到here最常用的访问它的函数,如fscanf(),fprintf()等 .

  • 0

    您的所有 fseek 电话都有效 . 您作为第二个参数提供的数字是偏移量,这意味着它相对于您提供的搜索类型作为第三个参数 .

    fseek(file, 4, SEEK_CUR);    // seek 4 bytes forward from current position
    fseek(file, -1, SEEK_END);   // seek to 1 byte before the end of the file
    fseek(file, 0, SEEK_CUR);    // does nothing.
    

    但另请参阅用户Tu.ma的解释,如果文件已在文本模式下打开(特别是在Windows下由于回车/换行翻译),搜索位置不准确和/或无意义 .

  • 1

    没有什么可以阻止你使用fseek超越文件的当前大小 . 因为这样做可以让你在那时写入数据,填补与NUL之间尚未写入的差距 . 与此示例代码一样 - 它创建一个包含1000个NUL的文件然后 "hello\n"

    #include <stdio.h>
    
    int main(void)
        {
        FILE *f;
    
        f=fopen("test","w"); 
        if(f)
            {
            fseek(f,1000,SEEK_SET);
            fprintf(f,"hello\n");
            fclose(f);
            }
        else
            {
            perror("fopen");
            }
        }
    
  • 2

    我认为 fseek 的定义与C标准一样的主要原因是文本文件中的逻辑位置可能与文本文件开头的物理字节数无关 .

    例如,在Windows实现中,将磁盘上的文件中的 \r\n 转换为 \n 以保持与Unix行结尾的兼容性并不罕见 . 所以如果你的文件是这样的:

    hello\r\nworld
    

    即两行,你 fseek 到位置6,你期望在 \nw ?如果您试图通过在Windows上使用 fgetc 来查找字符数,那么您可以假设您将使用 w . 但是 fseek 可能会在不扫描行结尾的情况下前进到字节6 .

    Edit

    如果我们使用fgetc函数,我们读取的每个字符都会增加1的位置:文件光标在读取前一个字符后转到下一个字符 . 那是一个问题?

    是 . 问题出在"character"的定义中 . 如果您所在的环境使用DOS约定,则当接下来的两个字节为 0x0d 0x0a 时,在文本流上使用 fgetc 将文件位置提前2,但仅返回 0x0a . 实现可能会进行其他转换,例如将分解的Unicode转换为预合成的unicode,反之亦然 .

    C标准中的措辞允许实现丢失文件中的字节与 fgetc 返回的字符之间的一对一映射,而不必过度复杂化 fseek .

相关问题