C - 如果达到 EOF,为什么 fread() 有两种可能的行为?

use*_*671 2 c

我不明白为什么函数 fread() 在这两个示例中表现不同:

1)
我有一个带有short和char的结构(大小为4个字节,包括填充)和一个由三个这样的结构组成的数组。如果我用fwrite()分别写入每个结构的每个short和char,然后用fread读取该文件() 对于一个类型为该结构的变量,我将一次读取 4 个字节(文件中将有 9 个字节),因此您可以看到在第 3 次迭代中将留下一个字节(并且在第 3 次迭代中将丢失一个字节)每次迭代)。发生的情况是没有第三次读取,因为我只剩下一个字节,而 fread 必须读取 4 个字节。

2)
一个更简单的例子,如果我使用 fwrite() 将 1 字节字符写入文件,然后使用 fread() 将该文件的内容放入 4 字节 int 中,则整数将获取该数据。

为什么会发生这种情况?如果达到 EOF,为什么在一种情况下会读取数据,而在另一种情况下却不会读取数据?

这是第一个例子:

int main()
{
    struct X { short int s; char c; } y, x[]=
    {{0x3132,'3'},{0x3435,'6'},{0x3738,'9'}};
    FILE *fp=fopen("FILE.DAT","wb+");
    if (fp)
    {
        for(int i=0;i<sizeof(x)/sizeof(x[i]);)
        {
            fwrite(&x[i].s,sizeof(x[i].s),1,fp);
            fwrite(&x[i].c,sizeof(x[i].c),1,fp);
            i++;
        }
        rewind(fp);
        for(int i=0;fread(&y,sizeof(y),1,fp);)
        printf("%d:%x %c\n",++i, y.s, y.c);
        fclose(fp);
    }
return 0;
}  
Run Code Online (Sandbox Code Playgroud)

第二个例子:

int main()
{
    FILE *fp=fopen("FILE.DAT","wb+");
    char c = 'a';
    fwrite(&c, sizeof(c), 1, fp);
    rewind(fp);

    int num;
    fread(&num, sizeof(num), 1, fp);
    fclose(fp);

return 0;
}  
Run Code Online (Sandbox Code Playgroud)

chu*_*ica 5

\n

如果达到 EOF,为什么在一种情况下可以读取数据,而在另一种情况下却不能读取数据?

\n
\n\n

“发生的情况是没有第三次读取,因为我只剩下一个字节,而 fread 必须读取 4 个字节。” 是一个值得怀疑的前提。

\n\n

第一个代码确实读了 3 次。没有剩余字节可供读取。

\n\n

在这两个代码中,最后一次读取都是部分读取,fread()返回值为 0。@Useless
\n(第一个代码没有打印第三次读取的结果。)

\n\n

对于fread(),返回值 0 并不意味着立即遇到“文件结束” - 没有读取任何内容。相反,0 表示由于以下原因未发生完整读取:
\n * “文件结束”或部分读取。
\n * 罕见的 I/O 错误。

\n\n
\n\n
\n

为什么会出现这种情况?

\n
\n\n

在第二个代码中,由于不确定行为,结果可能会有所不同

\n\n
\n

fread()...如果读取部分元素,则其值不确定1 C11dr \xc2\xa77.21.8.1 2

\n
\n\n

fread(&num, sizeof(num), 1, fp)结果可能会或可能不会达到预期。

\n\n

一个信息更丰富的例子

\n\n
int main(void) {\n  FILE *fp = fopen("FILE.DAT", "wb+");\n  char c = \'a\';\n  printf("  %8X\\n", c);\n  fwrite(&c, sizeof(c), 1, fp);\n  rewind(fp);\n\n  unsigned num = rand();\n  printf("  %8X\\n", num);\n  size_t len = fread(&num, sizeof(num), 1, fp);\n  printf("%zu %8X\\n", len, num);\n  len = fread(&num, sizeof(num), 1, fp);\n  printf("%zu\\n", len);\n  fclose(fp);\n\n  return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

输出

\n\n
        61  as expected\n  5851F42D  as expected - some random value\n0 5851F461  Indeterminate!  (in this case, looks like the LSByte was replaced.)\n0           as expected\n
Run Code Online (Sandbox Code Playgroud)\n\n

fread()这个故事的寓意是:根据读入缓冲区的内容来评估 before 的返回值。

\n\n
\n\n

1 个 不确定值
\既不是未指定的值也不是陷阱表示

\n