对于某些编译器,有一个结构的包装说明符,例如::
RealView ARM compiler has "__packed" Gnu C Compiler has "__attribute__ ((__packed__))" Visual C++ has no equivalent, it only has the "#pragma pack(1)"
我需要一些可以放入 struct 定义的内容。
任何信息/黑客/建议? TIA ...
答案 0 :(得分:71)
你可以为GNU gcc
定义这样的PACK#define PACK( __Declaration__ ) __Declaration__ __attribute__((__packed__))
和Visual C ++一样:
#define PACK( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop) )
并像这样使用它:
PACK(
struct myStruct
{
int a;
int b;
});
答案 1 :(得分:27)
我不知道这样做的光滑方式,但你可能会做这样可怕的事情:
#include "packed.h"
struct Foo { /* members go here */ } PACKED;
#include "endpacked.h"
然后对于MSVC,packed.h:
#define PACKED
#pragma pack(push,1)
endpacked.h
#pragma pack(pop)
#undef PACKED
对于gcc,packed.h:
#define PACKED __attribute__ ((__packed__))
endpacked.h:
#undef PACKED
从根本上说,包装过于依赖平台。假设您的压缩结构中包含8位字段,并考虑一些具有16位字节的系统。它只能通过打包来形成一个表示数据的结构 - 你必须知道在两个系统之间传输时如何将8位字节转换为16位字节。 16位机器上的结构可能需要位域,在这种情况下,您必须知道实现如何将它们排出。
因此,如果代码通常是可移植的,您可能只需要在头文件的特定于平台的部分中定义所需的任何打包结构。或者更确切地说,构造您的代码,以便未来的端口可以做到这一点。
答案 2 :(得分:15)
我知道这个问题现在已经过时了,但我相信有一个比之前发布的更好的解决方案。毕竟,可以将pragma放在结构声明行中的MSVC案例中。请考虑以下事项:
#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
然后可以这样使用:
typedef PACKED_STRUCT() { short a; int b } my_struct_t;
PACKED_SRUCT(my_other_struct) { short a; int b };
等
这里的关键是__pragma的使用只需要在struct的声明行周围。如果给出一个结构名称,则需要包含结构名称,因此该名称是宏的参数。当然,这很容易扩展到enum / class,我将把它作为练习留给读者!
pack documentation MSDN page上的测试程序对验证这一点非常有用。
修改强>
在我的测试中,我在Windows上使用了英特尔编译器。使用icl.exe这种方法没有问题,但使用Microsoft编译器(cl.exe),它没有(使用2010和2013测试)。
答案 3 :(得分:7)
你可以反过来这样做,因为GCC支持VC ++包相关的pragma。查看here了解更多信息。
...提取
为了与Microsoft Windows编译器兼容,GCC支持一组
JAVADOC_AUTOBRIEF
指令的更改,其中包含成员的最大对齐方式 结构(零宽度位域除外),联合和类 随后定义。下面的n值必须始终为a 小功率为2,并以字节为单位指定新对齐。
#pragma
只需设置新的对齐方式。
#pragma pack(n)
将对齐设置为有效时的对齐方式 编译已开始(另请参阅命令行选项#pragma pack()
参见Code Gen Options)。
-fpack-struct[=<n>]
按下当前对齐设置 内部堆栈然后可选地设置新的对齐。
#pragma pack(push[,n])
将对齐设置恢复为保存的设置 内部堆栈的顶部(并删除该堆栈条目)。请注意,
#pragma pack(pop)
不会影响此内部堆栈; 因此可以使#pragma pack([n])
后跟多个#pragma pack(push)
个实例,由一个#pragma pack(n)
最终确定。某些目标,例如i386和powerpc,支持
#pragma pack(pop)
ms_struct
它将结构列为记录的#pragma
。
__attribute__((ms_struct))
打开声明的结构的布局。
#pragma ms_struct on
关闭了声明的结构的布局。
#pragma ms_struct off
返回默认布局。
答案 4 :(得分:6)
根据您需要支持的编译器,另一个解决方案是注意到GCC至少支持Microsoft风格的打包编译,因为至少版本4.0.4(在线文档可以从gnu.org获得版本3.4.6和4.0.4 - 前者没有描述编译指示,后者中描述了编译指示。这使您可以在结构定义之前使用#pragma pack(push,1)
,在定义之后使用#pragma pack(pop)
,它将在任何一个中编译。
答案 5 :(得分:2)
为什么在结构中需要一些东西?
我认为#pragma pack(1)
是相同的,或者我错过了什么?
你可以这样做:
struct Foo
{
#pragma pack(push, 1)
int Bar;
#pragma pack(pop)
};
但它看起来很难看。