C++ visualc&x2B+;相当于GCC';s_uuu属性_uuu((uuu压缩_uuu))

C++ visualc&x2B+;相当于GCC';s_uuu属性_uuu((uuu压缩_uuu)),c++,c,visual-c++,gcc,data-structures,C++,C,Visual C++,Gcc,Data Structures,对于某些编译器,结构有一个打包说明符,例如: RealView ARM compiler has "__packed" Gnu C Compiler has "__attribute__ ((__packed__))" Visual C++ has no equivalent, it only has the "#pragma pack(1)" RealView ARM编译器已“打包” GNUC编译器具有“\uuuuu属性”((\uuuuu压缩的\uuuuuu))” Visual C++没有等价

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

RealView ARM compiler has "__packed" Gnu C Compiler has "__attribute__ ((__packed__))" Visual C++ has no equivalent, it only has the "#pragma pack(1)" RealView ARM编译器已“打包” GNUC编译器具有“\uuuuu属性”((\uuuuu压缩的\uuuuuu))” Visual C++没有等价性,它只具有“γ-语用包(1)”。 我需要一些可以放入结构定义中的东西


有什么信息/黑客/建议吗?TIA…

为什么需要一些东西进入结构

我觉得
#pragma pack(1)
是一样的,还是我遗漏了什么

您可以这样做:

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

但是它看起来很难看。

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

#include "packed.h"
struct Foo { /* members go here */ } PACKED;
#include "endpacked.h"
PACK(struct myStruct
{
    int a;
    int b;
});
然后对于MSVC,打包。h:

#define PACKED
#pragma pack(push,1)
#define PACKED __attribute__ ((__packed__))
endpacked.h

#pragma pack(pop)
#undef PACKED
对于gcc,包装。h:

#define PACKED
#pragma pack(push,1)
#define PACKED __attribute__ ((__packed__))
endpacked.h:

#define PACKED
#pragma pack(push,1)
#define PACKED __attribute__ ((__packed__))
#undef PACKED
从根本上说,打包过于依赖于平台。假设您的打包结构中有8位字段,并考虑一些具有16位字节的系统。它不能仅仅通过打包就拥有一个表示数据的结构——您必须知道在两个系统之间传输时,8位字节如何转换为16位字节。16位机器上的结构可能需要位字段,在这种情况下,您必须知道实现如何布局它们


因此,如果代码打算一般可移植,那么您可能只需要在头文件的平台特定部分中定义所需的任何打包结构。或者更确切地说,构建您的代码,以便将来的端口在必要时可以这样做。

您可以为
GNU GCC
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
然后像这样使用它:

#include "packed.h"
struct Foo { /* members go here */ } PACKED;
#include "endpacked.h"
PACK(struct myStruct
{
    int a;
    int b;
});

我知道这个问题现在已经过时了,但我相信有一个比之前发布的更好的解决方案。毕竟,可以将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_STRUCT(my_other_struct) { short a; int b };
等等

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

上的测试程序有助于验证这一点

编辑


在我的测试中,我使用的是Windows上的英特尔编译器。使用icl.exe这种方法可以毫无问题地工作,但对于Microsoft编译器(cl.exe),则没有问题(在2010年和2013年进行了测试)。

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

您可以以另一种方式进行编译,因为GCC支持与VC++包相关的pragma。请查看更多信息

摘录

为了与Microsoft Windows编译器兼容,GCC支持 更改 结构(零宽度位字段除外)、联合和类 随后定义。下面的n值始终要求为a 较小的二次幂,以字节为单位指定新的对齐方式

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

#pragma pack()
将对齐设置为在 编译已开始(另请参见命令行选项
-fpack struct[=]
请参见代码生成选项)

#pragma pack(push[,n])
将当前对齐设置推送到 内部堆栈,然后可以选择设置新的对齐方式

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

请注意,
#pragma pack([n])
不会影响此内部堆栈; 因此,可以将
#pragma pack(push)
后跟多个
#pragma pack(n)
实例,并由单个
#pragma pack(pop)
完成

一些目标,例如i386和powerpc,支持
ms_结构
#pragma
它以文档化的
\uuuuu属性((ms\u struct))
的形式布置结构

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

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

#pragma ms_struct reset
返回默认布局


它实际上是#pragma pack(push,1)和#pragma pack(pop)。@Caspin:我想打包整个结构。@其他:我想定义一个#define(事实上是2)为了在编译器中实现这一点,我将使用。#pragma技巧在其中一些编译器上不起作用。请注意,至少从4.0版开始,gcc就支持
#pragma pack
;不确定RealView ARM。从技术上讲,您可以在一个标题中完成所有这些:
#ifndef PACKED
/
#define PACKED
/
#else/*!PACKED*/
/
#undef PACKED
/
#endif/*PACKED*/
然后包含相同的头两次,一次启用,一次禁用。这种做法的有用性/清洁性/合理性是有争议的,但您建议的做法也是如此。我想我会选择“开始/结束必须匹配”,而不是“必须执行偶数次”,谢谢;-)。正如我在回答中所说,原则上您需要一个特定于平台的结构定义。但实际上,这涵盖了提问者目前关心的三个编译器,它允许更多的通用性,而不仅仅是大量的复制/粘贴,而且与大量的
#if#WIN32#elif相比,这并不可怕__