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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1537964/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 20:19:57  来源:igfitidea点击:

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

c++cvisual-c++gccdata-structures

提问by Malkocoglu

For some compilers, there is a packing specifier for structs, for example ::

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

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

I need something that I can put into the structdefinition.

我需要一些可以放入结构定义中的东西。

Any info/hack/suggestion ? TIA...

任何信息/黑客/建议?蒂亚...

采纳答案by Steve Jessop

I don't know a slick way of doing it, but you could possibly do something horrible like this:

我不知道这样做的巧妙方法,但你可能会做一些像这样可怕的事情:

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

Then for MSVC, packed.h:

然后对于 MSVC,packed.h:

#define PACKED
#pragma pack(push,1)

endpacked.h

封装的.h

#pragma pack(pop)
#undef PACKED

For gcc, packed.h:

对于 gcc,packed.h:

#define PACKED __attribute__ ((__packed__))

endpacked.h:

endpacked.h:

#undef PACKED

Fundamentally, packing is too platform-dependent. Suppose your packed struct has 8-bit fields in it, and consider some system with a 16-bit byte. It can't have a struct representing your data just by packing - you'd have to know how 8-bit bytes are converted to 16-bit bytes when transferred between the two systems. The struct on the 16bit machine might need bitfields, in which case you'd have to know how the implementation lays them out.

从根本上说,打包太依赖平台了。假设您的打包结构中有 8 位字段,并考虑一些具有 16 位字节的系统。它不能仅通过打包来表示您的数据的结构 - 您必须知道在两个系统之间传输时如何将 8 位字节转换为 16 位字节。16 位机器上的结构可能需要位域,在这种情况下,您必须知道实现如何布置它们。

So if the code is intended to be generally portable, you may just have to define whatever packed structures you need in a platform-specific section of your header file. Or rather, structure your code so that a future port can do that if it has to.

因此,如果代码通常是可移植的,您可能只需要在头文件的特定于平台的部分中定义您需要的任何打包结构。或者更确切地说,构建您的代码,以便将来的端口可以在必要时执行此操作。

回答by Steph

You can define PACK like as follows for GNU GCCand MSVC:

您可以为GNU GCCand定义 PACK 如下MSVC

#ifdef __GNUC__
#define PACK( __Declaration__ ) __Declaration__ __attribute__((__packed__))
#endif

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

And use it like this:

并像这样使用它:

PACK(struct myStruct
{
    int a;
    int b;
});

回答by Sam Jansen

I know this question is old now, but I believe there is a better solution than those posted earlier. It is possible to put the pragma in the MSVC case in the struct declaration line after all. Consider the following:

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

#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

Then this can be used like so:

然后可以像这样使用:

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

etc.

等等。

The key here is that the use of the __pragma only needs to be around the declaration line of the struct. This needs to include the struct name if it is given one, hence the name being a parameter to the macro. Of course, this is easy to extend to enum/class, which I'll leave as an exercise to the reader!

这里的关键是 __pragma 的使用只需要在结构的声明行周围。如果给出了结构名称,则需要包括结构名称,因此名称是宏的参数。当然,这很容易扩展到 enum/class,我将把它作为练习留给读者!

The test program on the pack documentation MSDN pageis useful to verify this.

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

EDIT

编辑

It turns out in my testing I was using the Intel Compiler on Windows. Using icl.exe this approach works without a problem, but with the Microsoft compiler (cl.exe), it does not (tested with 2010 and 2013).

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

回答by Autodidact

You can do it the other way round since GCC supports the VC++ pack related pragmas. Look herefor more information.

你可以反过来做,因为 GCC 支持与 VC++ 包相关的编译指示。看这里了解更多信息。

Extract...

提炼...

For compatibility with Microsoft Windows compilers, GCC supports a set of #pragmadirectives 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[=<n>]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#pragmawhich lays out a structure as the documented __attribute__((ms_struct)).

#pragma ms_struct onturns on the layout for structures declared.

#pragma ms_struct offturns off the layout for structures declared.

#pragma ms_struct resetgoes back to the default layout.

为了与 Microsoft Windows 编译器兼容,GCC 支持一组#pragma指令,这些指令可更改结构(零宽度位域除外)、联合和随后定义的类的成员的最大对齐方式。下面的 n 值总是要求是 2 的小幂,并以字节为单位指定新的对齐方式。

#pragma pack(n)只需设置新的对齐方式。

#pragma pack()将对齐设置为编译开始时生效的对齐(另请参阅命令行选项, -fpack-struct[=<n>]请参阅代码生成选项)。

#pragma pack(push[,n])将当前对齐设置推送到内部堆栈上,然后可选地设置新对齐。

#pragma pack(pop)将对齐设置恢复为保存在内部堆栈顶部的对齐设置(并删除该堆栈条目)。

注意,#pragma pack([n])不会影响这个内部堆栈;因此有可能#pragma pack(push)跟随多个 #pragma pack(n)实例并由单个#pragma pack(pop).

一些目标,例如 i386 和 powerpc,支持ms_struct#pragma按照记录的__attribute__((ms_struct)).

#pragma ms_struct on打开已声明结构的布局。

#pragma ms_struct off关闭已声明结构的布局。

#pragma ms_struct reset回到默认布局。

回答by Tom

Another solution, depending what compilers you need to support, is to notice that GCC has supported the Microsoft-style packing pragmas since at least version 4.0.4 (the online documentation is available at gnu.org for versions 3.4.6 and 4.0.4 - the pragmas are not described in the former and are in the latter). This lets you just use #pragma pack(push,1)before a structure definition and #pragma pack(pop)after the definition and it will compile in either.

另一个解决方案,取决于您需要支持的编译器,是注意 GCC 至少从 4.0.4 版开始支持 Microsoft 风格的打包编译指示(在线文档可在 gnu.org 上获得,适用于 3.4.6 和 4.0.4 版) - pragma 未在前者中描述,而在后者中)。这让您只需#pragma pack(push,1)在结构定义之前和定义#pragma pack(pop)之后使用,它就会在任何一个中编译。

回答by graham.reeds

Why do you need something to go in the struct?

为什么你需要在结构中添加一些东西?

I think #pragma pack(1)is the same, or am I missing something?

我认为#pragma pack(1)是一样的,还是我错过了什么?

You can do this:

你可以这样做:

struct Foo
{
#pragma pack(push, 1)
int Bar;
#pragma pack(pop)
};

But it looks ugly.

但它看起来很丑。