【发布时间】:2020-07-23 11:45:34
【问题描述】:
我有一个文件并使用 C 我想使用 fread()(来自 stdio.h)读取它的内容并将其写入结构的成员中。 (在我的例子中,开头有一个 2 字节的 int,后跟一个 4 字节的 int。) 但是在将文件内容正确写入结构的前两个字节变量后,它会跳过两个字节,然后继续执行第二个四字节变量。
为了演示,我创建了一个 16 字节的文件来读取。在十六进制中它看起来像这样(小端):
22 11 66 55 44 33 11 11 00 00 00 00 00 00 00 00
使用以下代码,我希望第一个变量twobytes 为0x1122,第二个变量fourbytes 为0x33445566。但它会打印:
twobytes: 0x1122
fourbytes: 0x11113344
sizeof(FOO) = 8
&foo : 0061FF14
&foo.two : 0061FF14
&foo.four: 0061FF18
跳过字节 3 和 4 (0x66 & 0x55)。代码:
#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;
}
使用具有两个相同大小整数的结构可以按预期工作。
所以:使用 fread() 写入不同大小的变量会导致跳过字节:
22 11 .. .. 44 33 11 11 ...
而不是
22 1166 55 44 33 ...
我知道字节对齐在此处发挥了作用,但这对字节的读取有何影响?如果 C 想要为结构添加填充,这对从文件中读取有何影响?
我不在乎 C 是否将结构成员存储为
22 11 .. .. 66 55 44 33 ...
或者
22 1166 55 44 33 ...,
我很困惑为什么它无法正确读取我的文件。
另外,我正在使用gcc version 6.3.0 (MinGW.org GCC-6.3.0-1)
【问题讨论】:
-
如果结构体 sizeof 是 8 个字节,那么它读取 8 个字节。
-
您应该检查/打印
sizeof(FOO)的值,它在您的代码中似乎是 8 个字节,并在两个结构成员之间添加了两个“缺失”字节作为填充。我认为您需要将__attribute__((__packed__))应用于结构的个人成员。 -
@Paul Tashkent,由于您询问的是非标准编译器扩展,因此您应该提及编译器及其版本
-
@PaulTashkent,没有理由认为
fread()会跳过任何字节。问题在于它将读取的字节放在哪里,以及它与struct的twobytes和fourbytes成员之间的关系。如果您在这些成员中的任何一个中都看不到预期的字节,那么唯一可能的答案是它们进入了这两个成员之间的结构中的填充字节。为什么你的编译器接受__attribute__((__packed__))却仍然用填充来布局结构是另一个问题。 -
This answer 也很有意思,推荐改用
#pragma pack。
标签: c struct byte fread struct-member-alignment