将C++结构填充为2的幂

Nic*_*yer 10 c++ struct bit-manipulation padding

我正在为嵌入式系统开发一些C++代码.代码使用的I/O接口要求每条消息的大小(以字节为单位)是2的幂.现在,代码执行类似的操作(在几个地方):

#pragma pack(1)
struct Message
{
   struct internal_
   {
      unsigned long member1;
      unsigned long member2;
      unsigned long member3;
      /* more members */
   } internal;
   char pad[64-sizeof(internal_)];
};
#pragma pack()
Run Code Online (Sandbox Code Playgroud)

我正在尝试首次在64位Fedora上编译代码,其中long64位.在这种情况下,sizeof(internal_)大于64,数组大小表达式下溢,并且编译器抱怨数组太大.

理想情况下,我希望能够编写一个宏来获取结构的大小,并在编译时评估填充数组所需的大小,以便将结构的大小舍入为2的幂.

我看过Bit Twiddling Hacks页面,但我不知道是否有任何技术可以在宏中实现,以便在编译时进行评估.

这个问题的任何其他解决方案?或者我应该延续这个问题,只需将神奇的64改为神奇的128?

fiz*_*zer 15

使用模板元程序.(编辑回应评论).

#include <iostream>
#include <ostream>
using namespace std;

template <int N>
struct P
{
    enum { val = P<N/2>::val * 2 };
};

template <>
struct P<0>
{
    enum { val = 1 };
};

template <class T>
struct PadSize
{
    enum { val = P<sizeof (T) - 1>::val - sizeof (T) }; 
};

template <class T, int N>
struct PossiblyPadded
{
    T       payload;
    char    pad[N]; 
};

template <class T>
struct PossiblyPadded<T, 0>
{
    T       payload;
};

template <class T>
struct Holder : public PossiblyPadded<T, PadSize<T>::val>
{
};


int main()
{
    typedef char Arr[6];

    Holder<Arr> holder;
    cout << sizeof holder.payload << endl;

    // Next line fails to compile if sizeof (Arr) is a power of 2
    // but holder.payload always exists
    cout << sizeof holder.pad << endl;
}
Run Code Online (Sandbox Code Playgroud)


bdo*_*lan 6

可能最明显的方法是使用三元运算符:

#define LOG2_CONST(n) ((n) <= 1 ? 0 :
                      ((n) <= 2 ? 1 :
                      ((n) <= 4 ? 2 :
                      /* ... */
                      ))))))))))))))))))))))))))))))
#define PADDED_STRUCT(ResultName, BaseName) \
  typedef union { BaseName data; char pad[1 << LOG2_CONST(sizeof(BaseName))]; } ResultName
Run Code Online (Sandbox Code Playgroud)


Nik*_*chi 5

为什么不使用工会?

union Message
{
    struct internal_
    {
        unsigned long member1;
        /* more members */
    };
    char[64];
};
Run Code Online (Sandbox Code Playgroud)

或者更好地使用匿名结构

union Message
{
    struct
    {
        unsigned long member1;
        /* more members */
    };
    char[64];
};
Run Code Online (Sandbox Code Playgroud)

所以你可以访问这样的成员:Message.member1;

编辑:显然这不能解决你的大于64的问题,但提供了一种更简洁的填充方式.


KPe*_*xEA 5

如何在发送和接收消息函数周围编写一个小包装器来处理任何大小的消息,它们只分配一个更大的缓冲区(下一个 2 的幂)并 memclear 它,将结构复制到开头并一起发送。