fread():从文件读取(不对齐)会导致字节跳过 [英] fread(): Reading from a file (without alignment) results in skipping of bytes

查看:146
本文介绍了fread():从文件读取(不对齐)会导致字节跳过的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个文件,使用C我想使用fread()(来自stdio.h)读取其内容并将其写入结构的成员中.(在我的情况下,开头是2字节int,然后是4字节int.)但是,在将文件的内容正确地写入结构的前两个字节变量后,它会跳过两个字节,然后继续第二个四个字节变量.

I have a file and using C I want to read the contents of it using fread() (from stdio.h) and write it into the members of a struct. (In my case there is a 2 byte int at the start followed by a 4 byte int.) But after writing the contents of the file correctly into the first two byte variable of the struct, it skips two bytes before continuing with the second four byte variable.

为了演示,我创建了一个16字节的文件以供读取.在十六进制中,它看起来像这样(小尾数法): 22 11 66 55 44 33 11 11 00 00 00 00 00 00 00 00

To demonstrate, I have created a 16 byte file to read from. In Hex it looks like this (Little-endian): 22 11 66 55 44 33 11 11 00 00 00 00 00 00 00 00

使用以下代码,我希望第一个变量 twobytes 0x1122 ,第二个变量 fourbytes 0x33445566 .而是打印:

With the following code I expect the first variable, twobytes, to be 0x1122 and the second, fourbytes, to be 0x33445566. But instead it prints:

twobytes: 0x1122 
fourbytes: 0x11113344

sizeof(FOO) = 8
&foo     : 0061FF14
&foo.two : 0061FF14
&foo.four: 0061FF18

跳过字节3和4( 0x66 & 0x55 ).代码:

Skipping bytes 3 and 4 (0x66 & 0x55). Code:

#include <stdio.h>
#include <stdint.h>

int main(void) {

    FILE* file = fopen("216543110.txt", "r");
    if (file==NULL) { return 1; }

    typedef struct
    {
        uint16_t twobytes;
        uint32_t fourbytes;
    }__attribute__((__packed__)) // removing this attribute or just the underscores around packed does not change the outcome
    FOO;
    
    FOO foo;
    
    fread(&foo, sizeof(FOO), 1, file);
    
    printf("twobytes: 0x%x \n", foo.twobytes);
    printf("fourbytes: 0x%x \n\n", foo.fourbytes);

    printf("sizeof(FOO) = %d\n", sizeof(FOO));
    printf("&foo     : %p\n", &foo);
    printf("&foo.two : %p\n", &foo.twobytes);
    printf("&foo.four: %p\n", &foo.fourbytes);
    
    fclose(file);
    return 0;
}

使用具有两个相同大小的整数的结构可以正常工作.

Using a struct with two same size integers works as expected.

因此:使用fread()写入不同大小的变量会导致跳过字节:

So: Using fread() to write into different size variables causes skipping bytes:

22 11 .. .. 44 33 11 11 ...

22 11 .. .. 44 33 11 11 ...

代替

22 11 66 55 44 33 ...

我知道字节对齐在这里起着一定的作用,但是这对字节的读取有何影响?如果C想要在结构中添加填充,这对文件读取有何影响?我不在乎C是否将struct成员存储为 22 11 .. .. 66 55 44 33 strong> ... 或者 22 11 66 55 44 33 ... ,我很困惑为什么它无法正确读取我的文件.

I am aware that something about byte alignment is playing a role here, but how does that affect the reading of bytes? If C wants to add padding to the structs, how does that affect the reading from a file? I don't care if C is storing the struct members as 22 11 .. .. 66 55 44 33 ... or 22 11 66 55 44 33 ..., I'm confused about why it fails to read my file correctly.

此外,我正在使用 gcc版本6.3.0(MinGW.org GCC-6.3.0-1)

推荐答案

在GCC上,定位x86平台时,

On GCC, when targetting x86 platforms, the

__ attribute __((__ packed __))

仅适用于具有

__ attribute __((gcc_struct)) .

但是,在面向Microsoft Windows平台时,结构的默认属性为

However, when targetting Microsoft Windows platforms, the default attribute for structs is

__ attribute __((ms_struct)).

因此,我看到了三种实现所需内容的方法:

Therefore, I see three ways to accomplish what you want:

  1. 使用编译器命令行选项 -mno-ms-bitfields ,以使所有结构默认为 __ attribute __((gcc_struct)).
  2. 在您的结构上明确使用 __ attribute __((gcc_struct)).
  3. 使用 #pragma pack 代替 __ attribute__((__packed __)).

此外,正如@chqrlie的答案所指出的那样,代码中还有其他一些不理想的东西.特别是在读取二进制数据时,通常应该以二进制模式而不是文本模式打开文件,除非您知道自己在做什么(因为文件扩展名为 .txt ,所以可能会这样做).

Also, as pointed out in the answer by @chqrlie, there are some other things not ideal in your code. Especially when reading binary data, you should normally open the file in binary mode and not text mode, unless you know what you are doing (which you possibly are, since the file has a .txt extension).

这篇关于fread():从文件读取(不对齐)会导致字节跳过的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆