我定义了以下结构(u8是unsigned char的typedef)
struct
{
u8 length_directory_record;
u8 extended_attribute_record;
u8 location_of_extend[8];
union
{
u8 bytes[8];
struct
{
long little;
long big;
} endian;
}
} dir;
现在当我像这样读取文件时
fseek(myfile, (SECTOR_SIZE*222)+34+34, 0);
fread_s(&dir, sizeof(dir), sizeof(u8), 18, myfile);
当我打印data_length值(小一点)时,我得到奇怪的大数字。该值实际存储为LSB和MSB(均为字节顺序),这就是我在联合中使用结构的原因。
printf("Data Length of File Section: %u\n", dir.data_length.endian.little);
然而,当我在没有阅读结构的情况下执行相同的步骤时,它可以工作:
union{
u8 val[4];
long v;
} value;
fseek(myfile, ((SECTOR_SIZE * 222) + 34 + 34)+10, 0);
fread_s(&value, sizeof(value), sizeof(u8), 4, myfile);
printf("%u\n", value.v);
我的第一个版本出了什么问题?为什么结构不正确填充或者我在这里没有看到任何问题?
编辑: 更多信息:我正在阅读的文件是二进制文件。 ((SECTOR_SIZE * 222)+ 34 + 34)是结构开始的位置。我使用十六进制编辑器验证了这一点(扇区大小为2048),因此第二个示例中的+10直接跳转到32位数的偏移量,存储为LSB和MSB(所以8个字节)
文件转储结构的偏移量:
30 00 DF 00 00 00 00 00 00 DF 30 C3 0B 00 00 0B C3 30 0.ß......ß0Ã....Ã0
data_length的预期值是770864字节,但此刻的输出是3862510(随机值)
答案 0 :(得分:1)
您的对象很可能没有像您期望的那样布局。这通常是由于编译器在结构中间插入了空格,因此它可以以最有效的方式访问结构成员。
以下是您的结构的可能布局:
struct dir {
uint8_t length_directory_record; // Stored at offset [0, 1)
uint8_t extended_attribute_record; // Stored at offset [1, 2)
uint8_t location_of_extend[8]; // Stored at offset [2, 10)
// Implicit padding // Stored at offset [10, 12)
union
{
uint8_t bytes[8]; // Stored at offset [12, 20)
struct
{
int32_t little; // Stored at offset [12, 16)
int32_t big; // Stored at offset [16, 20)
} endian;
};
};
从您的代码中可以看出,您希望在偏移10
找到联合。但它很可能是在偏移12
或16
找到的。
您可以使用以下方法验证dir.bytes
的实际偏移量:
assert(offsetof(dir, bytes) == 12);
此外,大多数编译器都提供了一种包装结构的机制,以便不存在隐式填充。通常,您使用#pragma pack
或__attribute__((packed))
。
我们还可以简化此错误,以便您更明显:
struct object {
uint8_t a;
uint32_t b;
};
此对象将占用8个字节的空间,并且在a
和b
之间将有3个字节的填充。
答案 1 :(得分:0)
这种问题经常发生在结构填料不匹配的情况下。字段之间的垃圾可能是由于当字段本身不是对齐大小时,编写器具有32位(或大)对齐字段。什么写在两者之间?随机残骸。
好像这个声明生效了:
#pragma pack (1)
struct {
u8 length_directory_record;
u8 cruft_area_1[3];
u8 extended_attribute_record;
u8 cruft_area_2[3];
u8 location_of_extend[8];
...