`fseek()` 函数中 `SEEK_CUR` 的零偏移用途是什么?

huangapple go评论72阅读模式
英文:

What is the use of zero offset in fseek() function with SEEK_CUR?

问题

while (fread(&product, sizeof(Product), 1, file) == 1) {
    product.price *= 2.0;
    fseek(file, -sizeof(Product), SEEK_CUR);
    fwrite(&product, sizeof(Product), 1, file);
    fseek(file, 0, SEEK_CUR);
}
英文:
while (fread(&product, sizeof(Product), 1, file) == 1) {
        product.price *= 2.0;
        fseek(file, -sizeof(Product), SEEK_CUR);
        fwrite(&product, sizeof(Product), 1, file);
        fseek(file, 0, SEEK_CUR);
}

Using the code above, I tried to double the price of each product in the binary file, where each record is an instance of a Product struct. When I ran this code, it updated all the prices in the file correctly.

As far as I know, fread automatically moves the file pointer to the next record. Using the first fseek, the code moves the file pointer back to the beginning of the record. Then it updates it using fwrite. fwrite automatically moves the file pointer to the next record. In the while loop, fread should continue to read the next record, and so on.

It seems that fseek(file, 0, SEEK_CUR); is unnecessary here. However, if I remove it, the code enters an infinite loop. I cannot figure out why this happens.

I tried to observe the value of file pointer using ftell. But I did not see any change its value after fseek(file, 0, SEEK_CUR);.

答案1

得分: 67

当流同时用于读取和写入时,不允许直接在读取和写入之间切换。ISO C11标准的§7.21.5.3 §7规定如下:

当以更新模式(在模式参数值的上述列表中作为第二或第三个字符的'+')打开文件时,可以对相关流执行输入和输出。但是,在进行输出操作后,不得直接进行输入操作,除非在调用fflush函数或文件定位函数(fseek、fsetpos或rewind)之间,而在进行输入操作后,不得直接进行输出操作,除非输入操作遇到文件结束。

如果删除以下行:

fseek(file, 0, SEEK_CUR);

那么您的程序将违反此规则,这将引发未定义行为。这意味着任何事情都可能发生,包括您的程序可能陷入无限循环。

英文:

When a stream is opened for both reading and writing, you are not allowed to directly switch between reading and writing. §7.21.5.3 ¶7 of the ISO C11 standard states the following:

> When a file is opened with update mode ('+' as the second or third character in the above list of mode argument values), both input and output may be performed on the associated stream. However, output shall not be directly followed by input without an intervening call to the fflush function or to a file positioning function (fseek, fsetpos, or rewind), and input shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file.

If you remove the line

fseek(file, 0, SEEK_CUR);

then your program violates this rule, which invokes undefined behavior. This means that anything can happen, which includes the possibility of your program getting stuck in an infinite loop.

答案2

得分: 7

以下是翻译好的部分:

一些文件系统,它们在执行随机查找时速度较慢,被设计成允许有效地处理一系列记录的读取-修改-写入操作,使用单独的读取和写入指针。像你的程序这样的程序可能完全可以省略fseek操作,前提是读取的数据量与写入的数据量匹配,并且在没有fseek()操作的情况下可能运行得更快。

C标准库的实现需要跟踪文件上一次操作是写入还是读取,以便相对fseek()可以相对于当前读取位置或当前写入位置操作,这取决于上一次执行的操作类型,但可以允许编写的程序利用双文件指针来获取相关的性能提升,以便在针对使用它们的系统时获得相关的性能提升。

虽然标准可以将在没有中间fseek()的情况下执行写入和读取的行为归类为实现定义,但这将被视为暗示实现应该在针对具有不始终可预测的边缘情况行为的平台时尝试以一致的文档方式行事。

英文:

Some file systems which are rather slow to perform random seeks are designed to allow efficiently process read-modify-write operations on a sequence of records by using separate read- and write pointers. A program such as yours might be able to omit the fseek operations entirely provided the amount of data read matched the amount of data written, and might run much faster without the fseek() operations than it would run if they were included.

A C Standard Library implementation would need to keep track of whether the last operation performed on a file was a write or a read, so that a relative fseek() could operate relative to either the the current read position or the current write position, depending upon which kind of operation was performed last, but could allow programs written to exploit dual file pointers to reap the associated performance gains when targeting systems that use them.

Although the Standard could have categorized the behavior of doing a write and read without an intervening fseek() as Implementation-Defined, that would have been seen as implying that implementations should try to behave in a consistent documented fashion even when targeting platforms with corner-case behaviors that aren't always predictable.

huangapple
  • 本文由 发表于 2023年5月14日 11:58:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/76245752.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定