8

我正在运行以下代码:

#include<stdio.h>
#include<string.h>
#include<io.h>

int main(){
    FILE *fp;
    if((fp=fopen("test.txt","r"))==NULL){
        printf("File can't be read\n");
        exit(1);
    }
    char str[50];
    fgets(str,50,fp);
    printf("%s",str);
    return 0;
}

text.txt 包含:I am a boy\r\n

由于我在 Windows 上,它需要 \r\n 作为换行符,所以如果我从文件中读取它应该存储"I am a boy\n\0"在. 我正在使用 mingw 编译器。str"I am a boy\r\n"

4

3 回答 3

9

该行为取决于 c 库实现以及您传递给的模式fopenfopen 请参阅(fopen on MSDN) 上的 MSDN 文档中的此引用:

b - 以二进制(未翻译)模式打开;涉及回车和换行字符的翻译被禁止。

意思是,如果您使用 Microsoft c 库,并打开省略“b”的文件,则将从流中删除回车符。

由于您使用的是 mingw,因此您的编译器可能会链接到遵循 POSIX 标准的 GNU c 库。这就是 GNU 文档所说的fopen (gnu.org 上的 fopen)

opentype 中的字符 'b' 具有标准含义;它请求二进制流而不是文本流。但这对 POSIX 系统(包括 GNU 系统)没有影响。

结论:您省略了“b”模式字符,它以文本模式打开您的流。您在 Windows 上,但使用了 GNU c 库,它在文本和二进制模式之间没有区别。这就是为什么fgets同时读取回车和换行的原因。

于 2013-09-27T06:37:48.727 回答
5

由于我在 Windows 上,它需要 \r\n 作为换行符...

这个假设是错误的。C 标准将回车和换行视为两个不同的事物,如 C99 §5.2.1/3(字符集)所示:

[...] 在基本执行字符集中,应该有代表警告、退格、回车和换行的控制字符。[...]

fgets函数描述如下,在 C99 §7.19.7.2/2 中:

fgets 函数从 stream 指向的流中最多读取比 n 指定的字符数少 1 的字符到 s 指向的数组中。在换行符(保留)之后或文件结尾之后不会读取其他字符。在读入数组的最后一个字符之后立即写入一个空字符。

因此,当遇到 string 时I am a boy\r\n,符合要求的实现应该读取到该\n字符。\r没有可能基于平台丢弃实现的合理理由。

于 2012-10-07T14:23:01.113 回答
1

c 标准对以下内容中的文本流进行了说明:

可能必须在输入和输出上添加、更改或删除字符,以符合在主机环境中表示文本的不同约定。因此,流中的字符与外部表示中的字符之间不需要一一对应。只有在以下情况下,从文本流中读取的数据必须与之前写入该流的数据相比较: 数据仅包含打印字符和控制字符水平制表符和换行符;空格字符前面没有换行符;最后一个字符是换行符。

换句话说,如果一个文件以文本模式打开,一个实现可以在进出磁盘时随意添加、删除和修改控制字符。这显然是 microsoft 实现对回车所做的,但 gnu 实现却没有。

于 2021-03-19T08:57:53.660 回答