1

我有一个指定如下的结构

  • 成员 1,16 位
  • 成员 2,32 位
  • 成员 3,32 位

我将从文件中读取。我想直接从文件中读取到结构中。

问题是 C 编译器会将变量 m1、m2 和 m3 与 32 位的字边界对齐,因为我正在为以下结构声明使用 ARM Cortex M3:

typedef struct
{
    uint16_t m1;
    uint32_t m2;
    uint32_t m3;
}something;

直接从文件中读取会在 m2 和 m3 中放入错误的值,并且还会读取 2 个额外字节。

我已经破解了,目前正在使用以下效果很好:

typedef struct
{
    uint16_t m1;
    struct
    {
        uint16_t lo;
        uint16_t hi;
    }m2;
    struct
    {
        uint16_t lo;
        uint16_t hi;
    }m3;
}something;

然而,这看起来像一个非常肮脏的黑客。我不禁希望有一种更简洁的方法来强制编译器将 m2 和 m3 的一半放在不同的词中,但它可能不是最理想的。

我正在使用 arm-none-eabi-gcc。我知道位打包,但无法解决此优化问题。

编辑:原来我对位打包知之甚少:D

4

4 回答 4

3

您正在寻找的是packed属性。这将迫使 gcc 不对成员进行任何填充。取自GCC Online 文档

包装好的

此属性附加到枚举、结构或联合类型定义,指定用于表示该类型所需的最小内存。为结构和联合类型指定此属性等效于为每个结构或联合成员指定打包属性。在该行上指定 -fshort-enums 标志等效于在所有枚举定义上指定打包属性。

您只能在枚举定义的右花括号之后指定此属性,而不是在 typedef 声明中,除非该声明还包含枚举的定义。

所以你想要的是这样的:

typedef struct
{
    uint16_t m1;
    uint32_t m2;
    uint32_t m3;
} __attribute__ ((packed)) something;

此外,我建议使用编译时断言检查来确保结构的大小确实是您想要的。

于 2015-06-18T18:47:33.170 回答
1

也许#pragma pack(2)。那应该强制编译器使用 2 字节对齐

于 2015-06-18T18:43:14.213 回答
1

你不能直接从文件中读取这样的结构,你永远不应该尝试。错位可能会在某些架构上造成陷阱,您不应该依赖 pragma 来解决这个问题。

几乎(*)可移植的方式是将文件元素读入结构元素,除非您确定该结构是使用与您用于读取的相同架构和对齐方式(至少兼容)编写的。

因此,对于您的用例,我建议:

fread(&something.m1, sizeof(something.m1), 1, fd);
fread(&something.m2, sizeof(something.m2), 1, fd);
fread(&something.m3, sizeof(something.m3), 1, fd);

(*) 它几乎是可移植的,因为它假定不存在根据您的需要是否正确的字节序问题。如果您在一台机器或单一架构上,那很好,但是如果您在大端机器上编写结构并在小端机器上读取它,就会发生不好的事情......

于 2015-06-18T18:57:09.433 回答
0
__attribute__ ((aligned (2)));
于 2015-06-18T18:46:50.733 回答