如果 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 实现的情况下,非零值将是 -1
,errno
将设置为可能有助于澄清失败原因的值。
【讨论】:
【参考方案3】:在 linux(和一般的 unix)中,它会成功并返回从文件开头测量的新偏移量,但文件不会增加,直到您在该偏移量处写入内容。
您未写入的部分将作为零从文件中读回,但根据操作系统和文件系统,某些零可能不必占用硬盘驱动器上的空间。
【讨论】:
以上是关于如果 fseek 中的给定偏移量超出最后一个字符会发生啥的主要内容,如果未能解决你的问题,请参考以下文章
如果数组大小发生变化以及定义的宏如何在此处计算偏移量,为啥 C 结构中的字符数组的偏移量会有所不同? [复制]
拆分给定字节偏移量的 utf-8 编码字符串(python 2.7)
Python习题:给定一个字符串和一个偏移量,根据偏移量旋转字符串(从左向右旋转)。例:输入: str="abcdefg", offset = 3 输出: "efgab