【问题标题】:Compile size of a struct minus padding recusively递归地编译结构减去填充的大小
【发布时间】:2020-08-21 08:52:34
【问题描述】:

我有一个与question 类似的问题。 我想在编译时获取结构的大小,包括所有没有添加编译器特定填充的子结构。

struct Bar {
  BOOST_HANA_DEFINE_STRUCT(Bar,
      (std::uint8_t, a),
      (std::uint16_t, b)
   );
};

struct Foo {
  BOOST_HANA_DEFINE_STRUCT(Foo,
      (std::uint8_t, a),
      (std::uint16_t, b),
      (std::uint32_t, c),
      (std::uint64_t, d),
      (Bar, bar)
    );
};

template <typename T>
constexpr auto bytesize() -> size_t
{
 if constexpr (std::is_arithmetic<T>::value || std::is_enum<T>::value)
    return sizeof(T);
  else if constexpr (std::is_class<T>::value)
  {
    return hana::fold_left(
      hana::accessors<T>(), 0, [](auto total, auto member) {
        // I want to call bytesize recusively here:
        return bytesize<decltype(hana::second(member)(std::declval<T>()))>() + total;
      });
  }  
}

static_assert(bytesize<Foo>() == 18);

由于我不想包含填充,我希望结构 Foo 的大小为 18(包括子结构 Bar 的大小),但链接问题中的代码确实包含填充计算并给我一个 19 的大小。问题在于函数应该在它遇到的所有结构上递归调用字节大小。

可以在here 找到一个无法按预期工作的最小示例。

【问题讨论】:

标签: c++ c++17 boost-hana


【解决方案1】:

您对返回的类型有疑问,这不是您所期望的(额外的&amp;&amp;)。 std::decay_t 修复问题:

return hana::fold_left(
    hana::accessors<T>(), 0, [](auto total, auto member) {
        using member_type = std::decay_t<decltype(hana::second(member)(std::declval<T>()))>;
        constexpr auto member_size = bytesize<member_type>();

        return total + member_size;
    });

Demo

【讨论】:

    【解决方案2】:

    结构的大小比较多,因为有paddingalignment

    https://en.wikipedia.org/wiki/Data_structure_alignment

    gccclang 上,您可以使用__attribute__((__packed__))

    struct Bar {
      BOOST_HANA_DEFINE_STRUCT(Bar,
          (std::uint8_t, a),
          (std::uint16_t, b)
      );
    } __attribute__((__packed__));
    

    示例
    https://godbolt.org/z/odMTEs

    注意,在 x86 上,打包结构没有负面影响。至少无法衡量。

    在 Arm 上,它们的工作速度也“足够快”。

    但是在其他一些架构上,它们可能真的很慢,甚至可能“崩溃”CPU。

    【讨论】:

    • 我绝对知道填充,这就是为什么我使用 boost::hana 来循环结构的成员并分别获取成员的大小。我不想依赖某些编译器特定的属性来完成任务
    • 好吧。如果你打包它,它就可以工作。会不会是和花有关的东西?
    • 等等,现在编译。你修好了?
    • 2*1Byte + 2*2Byte + 4Byte + 8Byte = 18Byte
    • 我知道,但我认为宏添加了隐形成员
    猜你喜欢
    • 1970-01-01
    • 2014-05-22
    • 2011-09-15
    • 2016-09-18
    • 2012-08-22
    • 2020-07-26
    • 1970-01-01
    • 2018-10-28
    • 1970-01-01
    相关资源
    最近更新 更多