在fread_s期间,结构填充不正确

时间:2014-05-30 16:58:02

标签: c struct fread unions

我定义了以下结构(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(随机值)

2 个答案:

答案 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找到联合。但它很可能是在偏移1216找到的。

您可以使用以下方法验证dir.bytes的实际偏移量:

assert(offsetof(dir, bytes) == 12);

此外,大多数编译器都提供了一种包装结构的机制,以便不存在隐式填充。通常,您使用#pragma pack__attribute__((packed))


我们还可以简化此错误,以便您更明显:

struct object {
    uint8_t a;
    uint32_t b;
};

此对象将占用8个字节的空间,并且在ab之间将有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];

    ...