为什么fwrite写入的数据比我指定的多?

20
FILE *out=fopen64("text.txt","w+");
unsigned int write;
char *outbuf=new char[write];
//fill outbuf
printf("%i\n",ftello64(out));
fwrite(outbuf,sizeof(char),write,out);
printf("%i\n",write);
printf("%i\n",ftello64(out));

输出:

0
25755
25868

发生了什么事?我设置了write为25755,然后告诉fwrite将这么多字节写入文件,文件在开头,那么我现在的位置是在25755之外吗?


1
顺便说一下,你应该使用 size_t 来代替 unsigned int 作为 write 函数的参数。 - Chris Lutz
4
在C语言中,“new”运算符是做什么用的? - Chris Lutz
4个回答

33

如果您使用类似于DOS的系统(例如Windows),并且该文件未在二进制模式下打开,则行末将自动转换,并且每个“行”将添加一个字节。

因此,像@caf所指出的那样指定"wb"而不仅仅是"w"作为模式。这对类Unix平台没有影响,并且对其他平台会执行正确的操作。

例如:

#include <stdio.h>

#define LF 0x0a

int main(void) {
    char x[] = { LF, LF };

    FILE *out = fopen("test", "w");

    printf("%d", ftell(out));
    fwrite(x, 1, sizeof(x), out);
    printf("%d", ftell(out));

    fclose(out);
    return 0;
}

使用VC++:

C:\Temp> cl y.c
Microsoft (R) 32-bit C/C++ 优化编译器 Version 15.00.21022.08 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.
y.c Microsoft (R) 增量链接器 Version 9.00.21022.08 Copyright (C) Microsoft Corporation. All rights reserved.
/out:y.exe C:\Temp> y.exe 04

使用Cygwin gcc:

/cygdrive/c/Temp $ gcc y.c -o y.exe

/cygdrive/c/Temp $ ./y.exe
02

3
如果你想以二进制模式打开文件,就应该在 fopen() 中使用 "wb" 而不是 "w" - caf
根据 OP 在 [mingw][cygwin] 标签下的轻微存在,我怀疑这就是答案。 - Chris Lutz
这很奇怪,因为 cygwin 安装程序会询问要使用哪种类型的行尾(并推荐使用 Unix 风格)。 - Sinan Ünür
1
@Sinan - 是的,但是MinGW可能会使用本地换行符,在两个环境之间切换时可能会引起轻微的混淆。 - Chris Lutz
“在别人身上做正确的事情”不是正确的思考方式。DOS/CPM和UNIX只是在它们的架构中做出了不同的决策。DOS决定将回车和换行符的概念分开,而UNIX则决定将这些概念合并到换行符字符中。在UNIX中,“wb”和“w”之间没有真正的区别意味着您不能在“错误模式”下打开和关闭文件时犯下“神秘的错误”。另一方面,DOS将换行符和回车符的概念分开,这与线性打印机的语义相匹配。 - Paul Hsieh
从上下文中可以清楚地看出,“正确的事情”是依赖于平台的,并且在同一台计算机上的不同环境中可能会有所不同。 - Sinan Ünür

4
可能取决于您打开文件的模式。如果您将其作为文本文件打开,则在DOS / Windows系统中, \n 可能会被写成 \r\n 。但是,ftello64()可能只会给出二进制文件指针,其中会计算额外写入的 \r 字符。尝试清除任何 \n 数据的 outbuf [] 或尝试以二进制方式打开输出文件(使用"wb"而不是"w")。

2
变量write未初始化,因此数组的大小和写入的数量实际上是随机的。

我怀疑它在真正的代码中被初始化了,而且OP只是过度保护在公共网站上发布生产代码。 - Chris Lutz
是的,在重新阅读问题后,我同意这不太可能是原始问题的原因 - 我认为Sinan的答案可能是正确的。但是以防万一它确实是原始代码的直接副本,我会在这里留下我的答案。 - Graeme Perrow

0

有趣。在Windows VC++上运行良好,尽管ftello64被替换为ftell


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接