Visual C ++相当于GCC的__attribute__((__packed__))

Visual C++ equivalent of GCC's __attribute__ ((__packed__))

对于某些编译器,有一个用于结构的打包说明符,例如::

1
2
3
RealView ARM compiler has"__packed"
Gnu C Compiler has"__attribute__ ((__packed__))"
Visual C++ has no equivalent, it only has the"#pragma pack(1)"

我需要可以放入结构定义中的内容。

任何信息/黑客/建议吗? TIA ...


您可以为GNU GCCMSVC如下定义PACK:

1
2
3
4
5
6
7
#ifdef __GNUC__
#define PACK( __Declaration__ ) __Declaration__ __attribute__((__packed__))
#endif

#ifdef _MSC_VER
#define PACK( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop))
#endif

并像这样使用它:

1
2
3
4
5
PACK(struct myStruct
{
    int a;
    int b;
});


我不知道如何做到这一点,但是您可能会做这样的可怕事情:

1
2
3
#include"packed.h"
struct Foo { /* members go here */ } PACKED;
#include"endpacked.h"

然后对于MSVC,packed.h:

1
2
#define PACKED
#pragma pack(push,1)

打包

1
2
#pragma pack(pop)
#undef PACKED

对于gcc,packed.h:

1
#define PACKED __attribute__ ((__packed__))

endpacked.h:

1
#undef PACKED

从根本上讲,打包过于依赖平台。假设您的压缩结构中包含8位字段,并考虑某些具有16位字节的系统。它不能具有仅通过打包来表示数据的结构-您必须知道在两个系统之间传输时如何将8位字节转换为16位字节。 16位计算机上的结构可能需要位域,在这种情况下,您必须知道实现如何对其进行布局。

因此,如果代码通常是可移植的,则可能只需要在头文件的特定于平台的部分中定义所需的打包结构即可。或者更确切地说,对代码进行结构设计,以便将来的端口可以根据需要执行此操作。


我知道这个问题现在已经很老了,但我相信比以前发布的解决方案更好。毕竟,可以在struct声明行的MSVC案例中放入编译指示。考虑以下:

1
2
3
4
5
6
#ifdef _MSC_VER
#  define PACKED_STRUCT(name) \
    __pragma(pack(push, 1)) struct name __pragma(pack(pop))

#elif defined(__GNUC__)
#  define PACKED_STRUCT(name) struct __attribute__((packed)) name
#endif

然后可以这样使用:

1
2
typedef PACKED_STRUCT() { short a; int b } my_struct_t;
PACKED_STRUCT(my_other_struct) { short a; int b };

等等

这里的关键是__pragma的使用只需要在结构的声明行周围即可。如果给定结构名称,则需要包含该结构名称,因此该名称是宏的参数。当然,这很容易扩展到枚举/类,我将作为练习留给读者!

软件包文档" MSDN"页面上的测试程序可用于验证这一点。

编辑

事实证明,在我在Windows上使用Intel编译器的测试中。使用icl.exe,此方法可以正常工作,但使用Microsoft编译器(cl.exe),则不能(在2010和2013中测试)。


由于GCC支持与VC ++包相关的编译指示,因此您可以反过来进行操作。在这里查看更多信息。

提取...

For compatibility with Microsoft Windows compilers, GCC supports a set
of #pragma directives which change the maximum alignment of members of
structures (other than zero-width bitfields), unions, and classes
subsequently defined. The n value below always is required to be a
small power of two and specifies the new alignment in bytes.

#pragma pack(n) simply sets the new alignment.

#pragma pack() sets the alignment to the one that was in effect when
compilation started (see also command line option
-fpack-struct[=] see Code Gen Options).

#pragma pack(push[,n]) pushes the current alignment setting on an
internal stack and then optionally sets the new alignment.

#pragma pack(pop) restores the alignment setting to the one saved at
the top of the internal stack (and removes that stack entry).

Note that #pragma pack([n]) does not influence this internal stack;
thus it is possible to have #pragma pack(push) followed by multiple
#pragma pack(n) instances and finalized by a single #pragma pack(pop).

Some targets, e.g. i386 and powerpc, support the ms_struct #pragma
which lays out a structure as the documented __attribute__((ms_struct)).

#pragma ms_struct on turns on the layout for structures declared.

#pragma ms_struct off turns off the layout for structures declared.

#pragma ms_struct reset goes back to the default layout.


根据您需要支持的编译器的不同,另一种解决方案是注意到GCC至少从4.0.4版本开始就支持Microsoft样式的打包实用程序(在线文档可在gnu.org上找到3.4.6和4.0.4版本。 -编译指示在前者中没有描述,而在后者中)。这样,您就可以在结构定义之前使用#pragma pack(push,1),在结构定义之后使用#pragma pack(pop),它将在任一结构中进行编译。


为什么在结构中需要某些内容?

我认为#pragma pack(1)是相同的,还是我缺少什么?

你可以这样做:

1
2
3
4
5
6
struct Foo
{
#pragma pack(push, 1)
int Bar;
#pragma pack(pop)
};

但是看起来很丑。