【问题标题】:array take size of struct in union数组在联合中采用结构的大小
【发布时间】:2018-01-18 09:29:24
【问题描述】:

我正在处理的项目中有一个代表 USB 操纵杆报告的联合:

union {
    struct{
        uint8_t xaxis;
        uint8_t yaxis;
        uint8_t xraxis;
        uint8_t yraxis;
        uint8_t zraxis;
        uint8_t slider;

        uint8_t buttons8;
        uint8_t buttons16;
    };
    uchar buffer[8];
} report;

这样我可以轻松地将值放入结构成员并使用缓冲区成员通过 USB 发送该数据,但是我最终为不同的项目修改了这个联合(轴上的不同分辨率,更多/更少按钮等)所以我必须弄清楚结构的新大小是什么,以声明具有相同大小的数组。

有没有办法自动使数组大小相同?我想过使用sizeof,这需要我像这样更改结构:

union {
    struct _data{ // either this
        uint8_t xaxis;
        uint8_t yaxis;
        uint8_t xraxis;
        uint8_t yraxis;
        uint8_t zraxis;
        uint8_t slider;

        uint8_t buttons8;
        uint8_t buttons16;
    } data; // or this
    uchar buffer[8];
} report;

但是我不能再像这样将数据放入结构中:

report.xaxis = value;

而是:

report.data.xaxis = value;

我不想要的。

有没有办法干净利落地做到这一点?

【问题讨论】:

  • 不要使用未标记的结构。然后使用sizeof(structure tag) 作为维度。
  • @JonathanLeffler 你能详细说明一下吗?我看不出这如何让我避免不得不做类似report.data.xaxis = value
  • 就像 Lundin 在他的回答中显示的那样。区分允许您引用结构类型的结构标记和成员名称。您应该能够使用匿名结构,但您需要标签,以便您可以引用类型并获取其大小。
  • @JonathanLeffler - 如果它被标记,它不是一个匿名结构。至少不是根据n1570
  • @StoryTeller:标记的结构可以是联合的匿名成员,就像未标记的结构也可以一样。我要离开这里几个小时——我需要找个时间睡觉。但是,虽然未标记的结构是一种匿名的,但您可以拥有结构或联合的匿名元素,这些匿名元素可以是已标记或未标记的结构(或各种其他类型)。

标签: c arrays struct


【解决方案1】:

你可以使用 offsetof() 来处理结构中的最后一个元素

union
{
    struct data
    {
        uint8_t xaxis;
        uint8_t yaxis;
        uint8_t xraxis;
        uint8_t yraxis;
        uint8_t zraxis;
        uint8_t slider;

        uint8_t buttons8;
        uint8_t buttons16;
    };
    uint8_t buffer[offsetof(struct data, buttons16)+1];
} report;

【讨论】:

  • 我知道你在做什么,但如果最后一个成员更改或更改类型(可能是 uint16_t),它仍然需要一些摆弄
  • 请注意,结构的末尾可能有填充。如果您声明一个联合数组,则不考虑这一点可能会导致问题。例如:report arr[n]; memcpy(x, arr, 5*sizeof(arr[0].buffer)); // copy 5 items 之类的代码可能会严重失败。
  • 此代码遇到了与Lundinanswer(当前版本)中的代码遇到的相同问题。有关一些信息,请参阅我的comment
【解决方案2】:

第一步是获得一个标准的 C 编译器。然后你可以使用匿名结构。要获得数组的适当大小,请使用 struct 标记,该标记仅在 union 内部需要。

typedef union {
    struct data {
        uint8_t xaxis;
        uint8_t yaxis;
        uint8_t xraxis;
        uint8_t yraxis;
        uint8_t zraxis;
        uint8_t slider;
        uint8_t buttons8;
        uint8_t buttons16;
    }; 
    uint8_t buffer[sizeof(struct data)];
} report_t;

...

  report_t r; 
  r.xaxis = 123;

【讨论】:

  • 我确实收到警告“不声明任何东西”与迂腐
  • @JamesKent 您使用的是哪个编译器,它是如何配置的?这可以在旧版本的 gcc 上干净地编译,但支持 C11。
  • @AnttiHaapala gcc 4.9.1 -std=c11 -pedantic-errors -Wall -Wextra 编译干净。
  • 这真的是一个匿名的structure, standard-wise, is kinda debatable
  • @JamesKent stackoverflow.com/questions/8932707/… 他们需要 C11 支持。
【解决方案3】:

其他人在这里提出的解决方案会奏效。但是,它们都是 hack,因为您使用联合来轻松转换为字节。有一个更清洁的解决方案,那就是取消工会。只需将您的 struct 设为顶级类型,并让通过 USB 发送数据的函数获取 (void * data, size_t length) 的参数。然后,您可以轻松地通过 USB 发送任何数据类型。

【讨论】:

    猜你喜欢
    • 2020-02-08
    • 1970-01-01
    • 1970-01-01
    • 2015-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多