我想创建一个具有特定对齐的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标记之后,如the docs中所述,如下所示:
struct __attribute__ ((aligned (32))) MyStruct
{
// ...
};
因此我可以使这种语法工作:
ALIGNED_STRUCT(32) MyStruct
{
// ...
};
有没有人有更好的版本?其他想法? 我尝试了一些代码搜索,但没有找到任何有希望的东西。
更新:基于@John的评论,这是另一个可行的版本(我没有编译它,但文档表明这是一个好主意)
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
答案 0 :(得分:25)
我知道这个帖子已经很老了 - 但是它还没有被标记为已回答,所提到的解决方案并不是最容易使用的。 解决这个问题的最好方法是注意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 pack - >这适用于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;
}
希望这会有所帮助......
答案 1 :(得分:5)
新版本的GCC(4.8.1)和VC ++(VS2013)支持在struct
和标识符名称之间具有属性的通用语法。这可能是由于新的C ++ 11标准引入了alignas
关键字来完成编译器的alignment属性所做的相同工作;但是,alignas
只能使对齐比数据类型的自然对齐更严格,而编译器指令也可以使它更宽松。
旁白:在VS2013上alignof
和stdalign.h
不受支持;虽然VS2015支持alignof
和alignas
,但它仍然没有C ++标准cstdalign
(或其C对应部分)规定的标头;因此,应根据工具链版本手动检查可用性。这可能是由于Visual Studio对C语言的支持不足。海湾合作委员会,OTOH,拥有所有这些;标头,宏(__alignas_is_defined
和__alignof_is_defined
)和关键字(alignas
和alignof
)。
通过这些信息,我们可以定义一些有效且具有编译器通用语法的东西:
#ifdef _MSC_VER
# if (_MSC_VER >= 1800)
# define __alignas_is_defined 1
# endif
# if (_MSC_VER >= 1900)
# define __alignof_is_defined 1
# endif
#else
# include <cstdalign> // __alignas/of_is_defined directly from the implementation
#endif
#ifdef __alignas_is_defined
# define ALIGN(X) alignas(X)
#else
# pragma message("C++11 alignas unsupported :( Falling back to compiler attributes")
# ifdef __GNUG__
# define ALIGN(X) __attribute__ ((aligned(X)))
# elif defined(_MSC_VER)
# define ALIGN(X) __declspec(align(X))
# else
# error Unknown compiler, unknown alignment attribute!
# endif
#endif
#ifdef __alignof_is_defined
# define ALIGNOF(X) alignof(x)
#else
# pragma message("C++11 alignof unsupported :( Falling back to compiler attributes")
# ifdef __GNUG__
# define ALIGNOF(X) __alignof__ (X)
# elif defined(_MSC_VER)
# define ALIGNOF(X) __alignof(X)
# else
# error Unknown compiler, unknown alignment attribute!
# endif
#endif
使用上述
的客户端代码示例struct ALIGN(32) MyStruct
{
...
};
static_assert(ALIGNOF(MyStruct) == 32, "Error: MyStruct not on a 32-byte boundary!");