2011-11-16 98 views
1

我有一个在mac和linux上成功编译和运行的软件框架。我现在试图将它移植到windows(使用mingw)。到目前为止,我已经在Windows下编译和运行了软件,但它不可避免地出现了错误。特别是,我在读取macos(或linux)中序列化的数据到程序的windows版本(segfaults)时遇到了问题。将数据序列化代码从C++ linux/mac移植到C++窗口

序列化过程将原始变量(长整数,整数,双精度等)的值序列化到磁盘。

这是我使用的代码:

#include <iostream> 
#include <fstream> 

template <class T> 
void serializeVariable(T var, std::ofstream &outFile) 
{ 
    outFile.write (reinterpret_cast < char *>(&var),sizeof (var)); 
} 

template <class T> 
void readSerializedVariable(T &var, std::ifstream &inFile) 
{ 
inFile.read (reinterpret_cast < char *>(&var),sizeof (var)); 
} 

所以就节省了一堆的变量的状态,我呼吁serializeVariable依次对于每个变量。然后为了读取数据,按照保存的顺序调用readSerializedVariable。例如保存:

::serializeVariable<float>(spreadx,outFile); 
::serializeVariable<int>(objectDensity,outFile); 
::serializeVariable<int>(popSize,outFile); 

,并阅读:

::readSerializedVariable<float>(spreadx,inFile); 
::readSerializedVariable<int>(objectDensity,inFile); 
::readSerializedVariable<int>(popSize,inFile); 

但在Windows,这个读取序列数据的失败。我猜测,Windows以不同的方式序列化数据。我想知道是否有办法修改上面的代码,以便保存在任何平台上的数据可以在任何其他平台上读取......任何想法?

干杯,

本。

+1

什么是T型?例如,我可以为不同的编译器考虑不同的sizeof(var)值 - 例如结构元素对齐的结果。想想另一个序列化机制,比如XML。例如, –

+0

这些类型是原始变量(请参阅编辑过的文章)。例如,我不知道编译器可能会为sizeof(long)产生不同的值。你确定?我的意思是,我认为总是4字节长,char总是1字节,独立于编译器等。 –

+1

是的,我们处理几个平台,一些长4字节,有些字节8字节。我相信该标准只规定了数据类型的最小值,而不是确切的字节数。 – Dan

回答

2

这样的二进制序列应该在这些平台做工精细。你必须尊重排序,但这是微不足道的。我认为这三个平台在这方面不存在任何冲突。但是,当你这样做时,你真的不能使用宽松的类型规范。 int,float,size_t尺寸可以全部在平台上改变。

对于整数类型,请使用cstdint标头中的严格尺寸类型。 uint32_t,int32_t等。Windows没有可用的iirc头文件,但您可以使用boost/cstdint.hpp。

浮点应该工作,因为大多数编译器遵循相同的IEEE规格。

C - Serialization of the floating point numbers (floats, doubles)

二进制序列确实需要彻底的单元测试。我强烈建议投入时间。

+0

谢谢汤姆。我真的想弄清楚我的实现正在发生什么。修复时会更新。 :-) –

+0

愚蠢的是,正如user103749所建议的那样,我会因为某种原因忘记在打开文件流时加入std :: ios :: binary。由于不用担心这个问题总是在linux和mac下运行,所以这个bug只是滑落了。很高兴我坚持使用这种序列化方法。干杯。 –

2

这只是一个疯狂的猜测,我不能帮你更多。我的想法是,字节顺序是不同的:大端与小端。因此,当装载到具有相反顺序的机器上时,大于一个字节的任何内容都会被搞乱。

例如我发现这个MSDN和平代码:

int isLittleEndian() { 
    long int testInt = 0x12345678; 
    char *pMem; 

    pMem = (char *) testInt; 
    if (pMem[0] == 0x78) 
     return(1); 
    else 
     return(0); 
} 

我想你会在Linux上,不同的结果VS窗口。最好的情况是如果你的编译器有一个标志选项使用一种格式或另一种格式。只需将其设置为在所有机器上相同。

希望这有助于 亚历

+0

谢谢亚历克斯,我将运行一些测试,以建立我的不同平台的字节顺序.. –

+0

好吧,似乎字节顺序是完全相同的两个我的Mac机器和我的Windows平台,所以我怀疑这个排序与它有什么关系。尽管如此,谢谢.. –

+0

丹也许是对的,那就是问题。特别是int并不一定要在通常情况下接近4个字节的地方。不幸的是,我没有任何第一手经验。顺便说一句。阅读失败是什么意思?对于任何数据类型?错误的值或错误? – Fritz

0

你有没有考虑使用序列库或格式,例如像:

  • XDR(由libc的支持)或ASN1
  • s11n(C++的序列化库)
  • Json,一个非常简单的文本格式有许多库,例如JsonCppJansson,Jaula,....)
  • YAML,一个更强大的文本格式,与许多图书馆
  • 甚至XML,这是经常用于序列化的目的...

(和标量的系列化,htonl和伴侣程序应该帮助)

+0

感谢您的建议 - 我没有听说过这些想法,除了XML ...感谢您打开我的眼睛。我仍然会尝试我一直这样做的方式,尽管因为在我眼里它应该工作......当我修复时会更新:-) –

1

只需再胡乱猜测: 你忘了二进制阅读模式打开的文件,并在Windows文件流 转换序列13,10至10.

+0

我的歉意,但我完全不知道你的意思。你能澄清一点吗? –

+1

我的意思是你在Windows上打开文件流时使用类似std :: ios :: binary的东西吗? – fghj

+0

感谢您的建议。我意识到在一些地方,我确实已经忘记了使用std :: ios :: binary。我对此感到有点无聊,但现在看起来一切正常,序列化按预期工作:-) –