10

組み込みシステム用の 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()

初めて64ビットのFedoraでコードをコンパイルしようとしていますlong.64ビットです。この場合、sizeof(internal_)は 64 より大きいため、配列サイズの式がアンダーフローし、コンパイラは配列が大きすぎると警告します。

理想的には、構造体のサイズを取得し、コンパイル時にパディング配列の必要なサイズを評価して、構造体のサイズを 2 の累乗に丸めるマクロを記述できるようにしたいと考えています。

私はBit Twiddling Hacksのページを見てきましたが、そこにあるテクニックのいずれかが実際にマクロに実装され、コンパイル時に評価されるかどうかはわかりません。

この問題に対する他の解決策はありますか? それとも、問題を永続させて、魔法の 64 を魔法の 128 に変更する必要がありますか?

4

11 に答える 11

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;
}
于 2009-08-06T16:26:12.157 に答える
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
于 2009-08-06T16:00:09.950 に答える
5

なぜ労働組合を使わないのですか?

union Message
{
    struct internal_
    {
        unsigned long member1;
        /* more members */
    };
    char[64];
};

または、匿名の構造体を使用することをお勧めします

union Message
{
    struct
    {
        unsigned long member1;
        /* more members */
    };
    char[64];
};

したがって、次のようにメンバーにアクセスできます。

編集:明らかに、これは64を超える問題を解決しませんが、パディングのよりクリーンな方法を提供します。

于 2009-08-06T15:58:53.930 に答える
4

任意のサイズのメッセージを処理する送信および受信メッセージ関数の周りに小さなラッパーを記述し、より大きなバッファー (次の 2 の累乗) を割り当てて memclear し、構造体を先頭にコピーして一緒に送信するのはどうですか。

于 2009-08-06T16:15:02.273 に答える
4

この問題を回避する 1 つの方法は、ハードコードされた 64 を size(long) の倍数に置き換えて、パディングを次のようにすることです。

char pad[4*sizeof(unsigned long) - sizeof(internal_)];

見苦しいですが、64 ビットに移植できるはずです。

とはいえ、メッセージ サイズが 2 のべき乗である必要がある API は、少し奇妙に聞こえ、設計上の問題のようです。サイズが偶数であることを要求することは、一部のプロセッサでは奇数アドレスのデータにアクセスするためにかなりのペナルティを支払うように理にかなっていますが、#pragma パックはそれをほとんど避けられません。

于 2009-08-06T16:01:55.827 に答える
2

あなたはすでに を使用しています。#pragma pack特に使用しているコンパイラはわかりませんが、配置/パディングを制御する pack の引数をサポートしているかどうかを確認してから、パディング フィールドを完全に取り除くことができます。GCC. _ pragma pack_ _

于 2009-08-06T17:13:24.123 に答える
0
union Message
{
    struct
    {
        unsigned long member1;
        unsigned long member2; //...
    };
    char pad[1 << 5]; //change 5 to whatever size you need...
};

少しきれいになります。

于 2009-08-06T16:24:19.090 に答える
0

さらに別のテンプレート ソリューション ( fizzerから大幅に奪う):

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

template <int TSize, int PSize = 1, bool = false>
struct PadSize
{
  static const int val =
    ( PadSize <    TSize, (PSize*2), (TSize <= (PSize*2)  )    > :: val );
};

template < int TSize, int PSize>
struct PadSize <TSize, PSize, true>  // As soon as TSize is <= to PSize
{
  static const int val = PSize;
};

int main()
{
    typedef char Arr[8];
    char pad[ PadSize <sizeof(Arr)>::val  ];

    cout << sizeof pad << endl;
}

私のアプローチは、少なくともタイプサイズと同じ大きさになるまで、パディングサイズを2倍にし続けることです。

于 2009-08-06T17:08:31.120 に答える
0

Niki's answer、特に匿名構造体の部分が好きです。

答えが解決しなかったことの 1 つは、64 バイトを超える問題でしたが、sizeof(long)==8 の場合はchar[128]構造体メンバーを条件付きで宣言し、それ以外の場合はchar[64]を宣言することで解決できます。

于 2009-08-06T16:28:32.637 に答える