在C++中,使用类读取二进制数据的最佳方法(不使用填充)。

3

我正在使用以下代码,使用C++类读取简单的二进制数据,不使用指针且没有填充:

#include <fstream>
#include <iostream>

using namespace std;

class Data {
    public:
    int a;
    int b;
    short int c;
    double d;
}__attribute__((packed));

int main() {
    Data myData;      
    ifstream ifs("test.bin", ios::binary);
    ifs.read((char *)&myData, sizeof(myData));
    ifs.close();
}

我使用这种方法是因为数据可能有20多种不同的格式,我想编写20多个不同的类来覆盖可能出现的所有格式。我还阅读到其他选项,包括使用位域、#pragma指令,甚至是boost序列化例程(我不能使用std)。我的问题是:使用类读取简单的二进制数据而不填充是否是最好的方法?您是否建议其他替代方法?我想了解哪种方法是最安全和最广泛使用的。


2
几乎没有其他方式同样简单有效。至少我不知道有其他方式。只需调用“Data”“struct”以获得良好的外观。 - Aneri
2
你的方法很好。你可以考虑使用#pragma pack(push,0)来让你的代码被更多编译器支持。但是,这两种方法都不能保证被C++支持。 - Drew Dormann
Drew,你的回答非常好,正是我想要的。我正在寻找一些编译器、跨平台、安全的东西。那么,pragma_pack更安全吗?你能再详细解释一下吗? - Jaime Ivan Cervantes
2个回答

2
通常情况下,人们会使用struct而不是class,但是,相同的概念适用于两者。

谢谢你的回答,但你确定使用结构体而不是类更好吗?我读到在C++中,建议使用类以保持一致。我还了解到类和结构体的主要区别在于类默认为私有,而结构体默认为公共。 - Jaime Ivan Cervantes
2
@JaimeCervantes 我看到的常见惯例是,当您拥有所有公共成员变量且未使用getter或setter时,通常会使用struct而不是class - andre

1

我使用这些宏来使紧凑的结构体在gcc和VC上都能编译:

#ifdef _MSC_VER
    #define BEGIN_PACK __pragma( pack(push, 1) )
    #define END_PACK __pragma( pack(pop) )
#else
    #define BEGIN_PACK 
    #define END_PACK __attribute__((packed))
#endif

那么,您可以像这样使用它们:

BEGIN_PACK
struct Data {
    int a;
    int b;
    short int c;
    double d;
} END_PACK;

但是,通常是这样做的。请注意,这些都是非标准扩展。

C++11已经定义了打包指令,但我不知道编译器是否支持它们。

1
是的,clang 也支持它,因为它与 gcc 兼容。但是,它是 gcc 的扩展功能。 - mfontanini
一些编译器有 pshpackX.hpoppack.h 头文件,其中 N 是所需的字节对齐方式(1、2、4、8 等),以隐藏特定于编译器的细节。 - Remy Lebeau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接