19

struct一定のアラインメントを持ったものを作りたいです。

GCCコンパイラとVisualC++コンパイラの両方に同じ構造体定義を使用したいと思います。

VisualC ++では、通常、これを行います。

__declspec(align(32))
struct MyStruct
{
// ...
};

GCCでは、通常、これを行います。

struct MyStruct
{
// ...
} __attribute__ ((aligned (32)));

もちろん、これを機能させるための適切なマクロを作成することもできます。

BEGIN_ALIGNED_STRUCT(32)
struct
{
// ...
}
END_ALIGNED_STRUCT(32)
;

したがって、両方のケースを透過的に処理できますが、ここでは、整列定数(32)を複製する必要があります。これは避けたいと思います。

GCCの代替手段は、ドキュメント__attribute__に記載されているように、次のようにstructタグの後に置くことです。

struct __attribute__ ((aligned (32))) MyStruct
{
// ...
};

したがって、このタイプの構文を機能させることができます。

ALIGNED_STRUCT(32) MyStruct
{
// ...
};

誰かより良いバージョンがありますか?他のアイデア?少しコード検索を試みましたが、あまり有望なものは見つかりませんでした。


更新: @Johnのコメントに基づいて、動作する可能性のある別のバージョンがあります(私はそれをコンパイルしていませんが、ドキュメントはそれがOKのアイデアであることを示しています)

struct MyStruct_Unaligned
{
// ...
};

TYPEDEF_ALIGNED(32, MyStruct_Unaligned, MyStruct);

// Would expand to one of:
// 
// typedef __declspec(align(32)) MyStruct_Unaligned MyStruct;
//
// typedef struct __attribute__ ((aligned (32))) MyStruct_Unaligned MyStruct
4

2 に答える 2

32

私はこのスレッドがかなり古いことを知っています-しかし、それはまだ答えとしてマークされておらず、言及された解決策は最も使いやすいものではありません。これを解決する最良の方法は、MSVCが宣言子の後にdeclspecを表示できるようにすることです。これが私自身の実装です:

#if defined(_MSC_VER)
#define ALIGNED_(x) __declspec(align(x))
#else
#if defined(__GNUC__)
#define ALIGNED_(x) __attribute__ ((aligned(x)))
#endif
#endif

#define _ALIGNED_TYPE(t,x) typedef t ALIGNED_(x)

/*SOME USAGE SAMPLES*/

ALIGNED_TYPE_(double, 16) aligned_double_t;

ALIGNED_TYPE_(struct, CACHE_LINE) tagALIGNEDSTRUCT
{
    /*STRUCT MEMBERS GO HERE*/
}aligned_struct_t;

ALIGNED_TYPE_(union, CACHE_LINE) tagALIGNEDUNION
{
    /*UNION MEMBERS GO HERE*/

}aligned_union_t;

次のコードでこれをテストできます(#pragmaパック->これはMSVC用であることに注意してください)

#if defined(_MSC_VER)
#define ALIGNED_(x) __declspec(align(x))
#else
#if defined(__GNUC__)
#define ALIGNED_(x) __attribute__ ((aligned(x)))
#endif
#endif

#define ALIGNED_TYPE_(t,x) typedef t ALIGNED_(x)

#pragma pack(1)
typedef struct tagSTRUCTPACKED
{
    int alignedInt;
    double alignedDouble;
    char alignedChar;
}struct_packed_t;
#pragma pack()

typedef struct tagSTRUCTNOALIGN
{
    int alignedInt;
    double alignedDouble;
    char alignedChar;
}struct_no_align_t;

typedef struct ALIGNED_(64) tagSTRUCTALIGNED64
{
    int alignedInt;
    double alignedDouble;
    char alignedChar;
}struct_aligned_64_t;


typedef struct tagSTRUCTWITHALIGNEDMEMBERS
{
    int ALIGNED_(8) alignedInt;
    double ALIGNED_(16) alignedDouble;
    char ALIGNED_(2) alignedChar;
}struct_with_aligned_members_t;

int main(int argc, char **argv)
{
    int i,j;
    struct_packed_t _packed;
    struct_no_align_t _noalign;
    struct_aligned_64_t _aligned64;
    struct_with_aligned_members_t _alignedmembers;

    char* names[] = {"_packed","_noalign","_aligned64","_alignedmembers"};
    char* ptrs[] = {(char*)&_packed,(char*)&_noalign,(char*)&_aligned64,(char*)&_alignedmembers};
    size_t sizes[] = {sizeof(_packed),sizeof(_noalign),sizeof(_aligned64),sizeof(_alignedmembers)};
    size_t alignments[] = {2,4,8,16,32,64};
    int alcount = sizeof(alignments)/sizeof(size_t);

    for(i = 0; i < 4; i++)
    {
        printf("Addrof %s: %x\n", names[i], ptrs[i]);
        printf("Sizeof %s: %d\n", names[i], sizes[i]);
        for(j = 0; j < alcount; j++)
            printf("Is %s aligned on %d bytes? %s\n", 
                names[i], 
                alignments[j], 
                ((size_t)ptrs[i])%alignments[j] == 0 ? "YES" : "NO");
    }

    for(j = 0; j < alcount; j++)
    {
            printf("Is _alignedmember.alignedInt aligned on %d bytes? %s\n", 
                    alignments[j], 
                    ((size_t)&_alignedmembers.alignedInt)%alignments[j] == 0 ? "YES" : "NO");
            printf("Is _alignedmember.alignedDouble aligned on %d bytes? %s\n", 
                    alignments[j], 
                    ((size_t)&_alignedmembers.alignedDouble)%alignments[j] == 0 ? "YES" : "NO");
            printf("Is _alignedmember.alignedChar aligned on %d bytes? %s\n", 
                    alignments[j], 
                    ((size_t)&_alignedmembers.alignedChar)%alignments[j] == 0 ? "YES" : "NO");
    }

    return 0;
}

お役に立てれば...

于 2012-09-29T17:25:42.500 に答える
9

最新のコンパイラについて

新しいバージョンのGCC(4.8.1)およびVC ++(VS2013)は、structと識別子名の間に属性を持つという一般的な構文をサポートしています。これはおそらくalignas、コンパイラのアライメント属性と同じ仕事をするために、新しいC++11標準でキーワードが導入されたためです。ただし、alignasデータ型の自然な配置よりも厳密に(広く)配置することしかできませんが、コンパイラ指令を使用すると、より寛大になります。これが、C ++ 11で導入されたalignas指定子(またはalignof演算子)よりもコンパイラー属性を好む理由です。

動作し、コンパイラ間で共通の構文を持つものを定義できます。

#if defined(__GNUC__) || defined(__clang__)
#  define ALIGN(x) __attribute__ ((aligned(x)))
#elif defined(_MSC_VER)
#  define ALIGN(x) __declspec(align(x))
#else
#  error "Unknown compiler; can't define ALIGN"
#endif

#if defined(__GNUC__) || defined(__clang__)
#    define ALIGNOF(X) __alignof__(X)
#elif defined(_MSC_VER)
#    define ALIGNOF(X) __alignof(X)
#else
#  error "Unknown compiler; can't define ALIGNOF"
#endif

上記を使用したクライアントコードの例

struct ALIGN(32) MyStruct
{
    ...
};

static_assert(ALIGNOF(MyStruct) == 32, "Error: MyStruct not on a 32-byte boundary!");
于 2015-08-13T06:45:53.467 に答える