Approach for automatic fields reordering in C-like structs
是否有一种方法可以在类C结构中执行自动字段重新排序?我的意思是使用语言特性(例如C和C++的预处理器和C++的模板/类型特征等),这使得可以执行下面的宏(Soop.Fusion风格,以适应结构):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | REARRANGE(StructureName, (int8_t)(FieldName1), (int32_t)(FieldName2), (int16_t)(FieldName3), (int32_t)(FieldName4)); // is equivalent to (without loss of generality): struct StructureName { int32_t FieldName2; int32_t FieldName4; int16_t FieldName3; int8_t FieldName1; }; |
当然,方法应该考虑到字段的
我知道结果的可移植性很差,但它只供本地使用。
必须将字段名与各自的类型一起保存。
目的是减小总结构尺寸。
我找到了C++ 14的解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | #include <boost/preprocessor/seq/for_each_i.hpp> #include <boost/preprocessor/repetition/enum.hpp> #include <utility> #include <cstddef> namespace details { template< std::size_t /*index*/, typename /*tag*/ > struct member; struct pair { std::size_t k, v; constexpr bool operator < (pair const & r) const { return r.k < k; } }; constexpr void swap(pair & l, pair & r) { pair m = r; r = l; l = m; } template< int N > constexpr void qsort(pair (&a)[N], int const l, int const r) { int i = l, j = r; pair pivot = a[l + (r - l) / 2]; while (!(j < i)) { while (a[i] < pivot) ++i; while (pivot < a[j]) --j; if (!(j < i)) { swap(a[i], a[j]); ++i; --j; } } if (l < j) qsort(a, l, j); if (i < r) qsort(a, i, r); } template< int N > struct map { pair a[N]; }; template< int N, std::size_t ...indices > constexpr map< N > make_map(pair (&a)[N], std::index_sequence< indices... >) { return {{a[indices]...}}; } template< int N > constexpr map< N > qsort(pair (&&a)[N]) { if (1 < N) { qsort< N >(a, 0, N - 1); } return make_map< N >(a, std::make_index_sequence< N >{}); } } #define GEN0(z, tag, index, type_name) template<> struct member< index, tag > \ { BOOST_PP_SEQ_HEAD(type_name) BOOST_PP_SEQ_HEAD(BOOST_PP_SEQ_TAIL(type_name)); }; #define GEN1(z, ignored, index, type_name) {sizeof(BOOST_PP_SEQ_HEAD(type_name)), index}, #define GEN2(z, index, tags) details::member< BOOST_PP_SEQ_HEAD(tags)::map.a[index].v, BOOST_PP_SEQ_HEAD(BOOST_PP_SEQ_TAIL(tags)) > #define GEN(ns, tag, members) \ namespace ns { struct tag; } \ namespace details { BOOST_PP_SEQ_FOR_EACH_I(GEN0, ns::tag, members) } \ namespace details::tags::ns { struct tag { static constexpr auto map = qsort({BOOST_PP_SEQ_FOR_EACH_I(GEN1, %%, members)}); }; } \ namespace ns { struct tag : BOOST_PP_ENUM(BOOST_PP_SEQ_SIZE(members), GEN2, (details::tags::ns::tag)(tag)) {}; } struct T { char c[3]; }; GEN(user::u2, S, ((char)(c))((int)(i))((T)(t))) #include <cassert> int main() { using namespace details; void(member< 0, user::u2::S >{}.c); void(member< 1, user::u2::S >{}.i); static_assert(tags::user::u2::S::map.a[0].k == 4); static_assert(tags::user::u2::S::map.a[1].k == 3); static_assert(tags::user::u2::S::map.a[2].k == 1); user::u2::S s{4, {'a', 'b', 'c'}, 'd'}; assert((void *)&s.i == (void *)&s); assert((void *)&s.t < (void *)&s.c); static_assert(sizeof(s) == 8); } |
- 对于MS编译器,使用pragma pack,(
#pragma pack(1) 消除了所有间隙)。并检查链接以获取详细信息,因为该指令并不保证始终有效。 - 对于GCC,有EDOCX1[1]
因为您的唯一目标是尽可能减小内存中数据的大小,所以这正是您所需要的。