【问题标题】:Why does C use 5 bytes to write/fwrite the number 10, but 4 bytes to write 9 or 11?为什么 C 使用 5 个字节来写入/fwrite 数字 10,而用 4 个字节来写入 9 或 11?
【发布时间】:2021-12-29 08:10:47
【问题描述】:

Windows 上的 GCC

#include <stdio.h>
#include <stdlib.h>

struct test {
    int n1;
    int n2;
};

int main() {
    FILE *f;
    
    f = fopen("test.dat", "w");
    struct test test1 = {10, 10};
    fwrite(&test1, sizeof(struct test), 1, f);
    fclose(f);
    
    struct test test2;
    f = fopen("test.dat", "r");
    while(fread(&test2, sizeof(struct test), 1, f))
        printf("n1=%d n2=%d\n", test2.n1, test2.n2);
    fclose(f);
    
    return 0;
}

如果我将 test1 设置为 10,10,那么 fwrite 会将 10 个字节 写入文件:0D 0A 00 00 00 0D 0A 00 00 00

(每个 4 字节的 int 将在其前面填充一个 0D 回车字符)

如果我将 test1 设置为 11,11,那么 fwrite 会将 8 个字节 写入文件:0B 00 00 00 0B 00 00 00

(如我所料)

如果我将 test1 设置为 9,9,那么 fwrite 会将 8 个字节 写入文件:09 00 00 00 09 00 00 00

(如我所料)

如果我将 test1 设置为 9,10,那么 fwrite 会将 9 个字节 写入文件:09 00 00 00 0D 0A 00 00 00

9 按预期获得 4 个字节,但 10 填充了一个额外的 0D 字节,结果为 5 个字节。需要这种填充的数字 10 有什么特别之处?为什么更小和更大的数字(8、9、11、12、13、14 等)都没有被填充?我想也许 GCC 混淆了换行符的数字 10(换行符是 10 是 acsii),但这并不能解释 fread 如何能够正确地恢复数字 10。

我如何将结构写入文件而不在数字 10 上获得额外的填充?

【问题讨论】:

  • 以文本模式打开文件时的行结束翻译。而是以二进制模式打开它。
  • 你在 Windows 上运行它,对吧?
  • f = fopen("test.dat", "wb");
  • 使用 WinHex 等外部工具查看输出文件。现在问题出在你的阅读上。
  • 这能回答你的问题吗? errors when writing to a bin file

标签: c struct fwrite


【解决方案1】:

您以 text 模式打开文件,因此在 Windows 上,每个 '\n' 字符前面都有一个回车符。

您应该改为在 binary 模式下写入(和读取)二进制数据 (fopen(..., "wb"))——这会更快,并且避免意外(并且也只需要 8 个字节,这就是sizeof(struct test) 是)。

需要这种填充的数字 10 有什么特别之处?

数字 10 恰好是换行符 ('\n') 的 ASCII 码。

【讨论】:

  • 以“wb”模式打开解决了这个问题。我很惊讶 C 在对数据执行此操作后能够正确地恢复 10 int。
【解决方案2】:

您正在以文本模式书写和阅读。

打开带有“wb”和“rb”标志的文件。这会将文件视为二进制文件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-11-13
    • 2020-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-18
    • 2011-11-01
    • 2021-04-10
    相关资源
    最近更新 更多