如果 fseek 中的给定偏移量超出最后一个字符会发生啥

Posted

技术标签:

【中文标题】如果 fseek 中的给定偏移量超出最后一个字符会发生啥【英文标题】:What will happen if the given offset in fseek goes beyond the last character如果 fseek 中的给定偏移量超出最后一个字符会发生什么 【发布时间】:2016-02-15 21:26:31 【问题描述】:

我目前正在使用 c++ 并尝试使用 fseek() 写入文件,以便写入从其他方法计算的给定偏移量。只是想知道如果给定的偏移量会使 FILE 指针超出文件中的最后一个字符会发生什么。

示例: 在以“abcdefg”为内容的文件中,fseek(someFILEpointer, 20, SEEK_SET) 会返回什么?

【问题讨论】:

【参考方案1】:

来自cppreference:

POSIX 允许在现有文件末尾之外进行查找。如果在此搜索之后执行输出,则从间隙中读取的任何内容都将返回零字节。在文件系统支持的情况下,这会创建一个稀疏文件。

听起来它应该返回非错误状态,但后续读取可能会失败。后续写入可能会成功,但具体行为可能取决于底层文件系统。

【讨论】:

换句话说,未定义的行为。它可能会导致您的计算机长出腿并加入非法骑车团伙。 @user4581301——好吧,不是真的。听起来它是经过定义的,并且在某种程度上依赖于实现。 在这里对你有点迂腐,这与你回答的质量无关。对于未来的读者来说,这更像是一个面包屑:在 C++ 和我使用过的所有其他语言中,如果语言标准中没有说明操作的结果,那么您就有未定义的行为。有时结果措辞不佳且易于解释,但要么已定义,要么未定义,标准的未来修订版将清理措辞。 我知道“未定义的行为”是什么意思。我的观点是,与许多其他标准一样,C++ 标准对 UB 和实现定义的行为进行了区分。这种特殊的边缘情况似乎是后者的一个实例。 不过,这里没有任何未定义或未指定的内容。如果您有一个 Posix 系统并且您将fseek 应用于常规文件,那么您可以 fseek 超出文件末尾并写入,任何跳过的字节随后将被读取为零。唯一未指定的部分是文件系统是否优化了零的存储; Posix 仅保证文件的行为就像它在“间隙”中存储了零一样。另一方面,C 标准将其保留为实现定义,您是否甚至可以执行带有 SEEK_END 偏移量的 fseek。【参考方案2】:

C 标准让它实现定义对fseek 的这种调用是否成功。如果无法按照指示的方式设置文件位置,fseek 将返回错误指示。

来自 C 标准:

二进制流不需要有意义地支持带有 SEEK_END 值的 fseek 调用。 (§7.21.9.2/3)

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

因此,在这两种情况下,您都不能保证能够以非零偏移量调用 fseek,并且将其设置为 SEEK_END

Posix 确实允许调用(引用自 description of fseek):

fseek() 函数应允许将文件位置指示符设置在文件中现有数据的末尾之外。如果此时稍后写入数据,则后续读取间隙中的数据应返回值为 0 的字节,直到数据实际写入间隙。

(Posix 将值 0 的字节是否实际存储或隐含由实现决定。大多数 Unix 文件系统实现稀疏文件,可以通过不在持久存储中存储零来优化这种情况,但这不是例如,可能在 FAT 文件系统上。)

即使是 Posix 也只对常规文件做出这种保证:

fseek() 在无法搜索的设备上的行为是实现定义的。与此类设备关联的文件偏移值未定义。

所以调用可能会失败,但这不是未定义的行为。如果无法重新定位,fseek 将返回一个非零值;在 Posix 实现的情况下,非零值将是 -1errno 将设置为可能有助于澄清失败原因的值。

【讨论】:

【参考方案3】:

在 linux(和一般的 unix)中,它会成功并返回从文件开头测量的新偏移量,但文件不会增加,直到您在该偏移量处写入内容。

您未写入的部分将作为零从文件中读回,但根据操作系统和文件系统,某些零可能不必占用硬盘驱动器上的空间。

【讨论】:

以上是关于如果 fseek 中的给定偏移量超出最后一个字符会发生啥的主要内容,如果未能解决你的问题,请参考以下文章

如果数组大小发生变化以及定义的宏如何在此处计算偏移量,为啥 C 结构中的字符数组的偏移量会有所不同? [复制]

Win32 - 如何获取给定系统光标位图的偏移量?

LintCode 8. 旋转字符串

随机存取:fseek(),ftell()

拆分给定字节偏移量的 utf-8 编码字符串(python 2.7)

Python习题:给定一个字符串和一个偏移量,根据偏移量旋转字符串(从左向右旋转)。例:输入: str="abcdefg", offset = 3 输出: "efgab