Linux和Windows之间fwrite的不同行为

时间:2015-06-29 12:47:24

标签: c linux windows fwrite

我有一个用C编写的小例子程序。我有一个调用函数writeFile的函数,它在二进制文件中写入一些数字。然后我调用overwrite将0替换为0,最后打印结果。

这是代码:

#include <stdio.h>

/* Print the content of the file */
void printFile(){
    printf("Read test.dat:\n");
    int r;
    FILE* fp = fopen("test.dat", "rb+");
    if(fp) {
    while(fread(&r,sizeof(int),1,fp)){
            printf("%d\n", r);
        }
    }
    fclose(fp);
}

/* Replace 0 with 1 */
void overwrite(){
    int   r;
    FILE *fp = fopen("test.dat", "rb+");
    if (fp) {
        int i=0;
        while (i < 4 && fread(&r, sizeof(int), 1, fp)) {
            i++;
            if (r == 0) {
                r = 1;
                fseek(fp,-sizeof(int),SEEK_CUR);
                fwrite(&r,sizeof(int),1,fp);
            }
        }
    }
    fclose(fp);    
}

/* Create original file */
void writeFile() {
    int b, b1, b2, b3, b4;

    b  = 3;
    b1 = 2;
    b2 = 0;
    b3 = 4;

    FILE *fp = fopen("test.dat", "wb");
    if (fp) {
        fwrite(&b, sizeof(int), 1, fp);
        fwrite(&b1, sizeof(int), 1, fp);
        fwrite(&b2, sizeof(int), 1, fp);
        fwrite(&b3, sizeof(int), 1, fp);
    }
    fclose(fp);    
}

int main() {
    writeFile();
    printf("---------BEFORE--------\n");
    printFile();
    printf("-----------------------\n");
    printf("Overwriting...\n");
    overwrite();
    printf("---------AFTER---------\n");
    printFile();
    return 0;
}

此代码适用于Linux,但是当我在Windows上运行相同的代码时,输​​出为:

 ---------BEFORE--------
Read test.dat:
3
2
0
4
-----------------------
Overwriting...
---------AFTER---------
Read test.dat:
3
2
1
2

不仅0被1替换,而且最后一个数字也被更改。有人可以帮我理解为什么会这样吗?

另一个问题是overwrite我必须使用i来停止,因为如果没有i<4我会得到一个无限循环(仅限Windows)。

我在使用gcc 4.8.1(来自MinGW)编译的Windows 8.1上测试了此代码。 在我的Linux机器上,我用gcc 5.1.1测试了代码。

谢谢大家,

2 个答案:

答案 0 :(得分:7)

这是因为您需要在fflush()之后fwrite(),因为在拨打fread()之后,如果没有对fwrite()进行干预,则不应致电fflush(),< / p>

这是与此案例相关的标准部分

  

7.21.5.3 fopen功能

     
      
  1. 当使用更新模式('+'作为上述模式参数值列表中的第二个或第三个字符)打开文件时,可以在关联的流上执行输入和输出。但是,如果没有输入,输出不应直接输入   干预对fflush函数或文件定位函数(fseekfsetposrewind)的调用,输入不应直接跟随输出而不是   干预调用文件定位功能,除非输入操作遇到文件结束。在某些实现中,打开(或创建)具有更新模式的文本文件可以改为打开(或创建)二进制流。
  2.   

这部分属于fopen()函数,这很奇怪,因为它涉及fread()fwrite(),这是我在寻找答案的地方。

您还可以看到我的http://jsfiddle.net/t68ajjnv/8/有效,但不是因为我在其中说明的原因,而是在上面的段落中找到了解释。

答案 1 :(得分:2)

Stream I/O的MSDN状态:

  

输入只能通过对fflush或文件定位功能(fseekfsetposrewind的干预调用直接跟随输出。如果输入操作遇到文件末尾,则输出可以跟随输入,而无需对文件定位函数进行干预。

所以你必须在调用fwrite后调用fflush()

void overwrite()
{
    FILE *fp = fopen("test.dat", "rb+");
    if (fp) {
        int   r;
        while (fread(&r, sizeof(int), 1, fp) == 1) {
            if (r == 0) {
                r = 1;
                fseek(fp,-sizeof(int),SEEK_CUR);
                fwrite(&r,sizeof(int),1,fp);
                fflush(fp); /* Flush here */
            }
        }
        fclose(fp); /* Also: call fclose() only when fopen() succeeded */
    }

}