【问题标题】:How to serialize / deserialize INTs in C++如何在 C++ 中序列化/反序列化 INT
【发布时间】:2021-05-04 07:27:06
【问题描述】:

所以,我想在 C++ 中为一些 int 变量实现简单的序列化,但我真的不知道如何......


我的目标如下:

我基本上希望能够将任何整数转换为二进制,最好是通过简单的函数调用。

// Here´s some dummy code of what I essentially want to do

int TestVariable = 25;
String FilePath = "D:\dev\Test.txt";

Serialize(TestVariable, FilePath);

// [...] 
// at some later point in the code, when I want to access the file

Deserialize(&TestVariable, FilePath);


我已经听说过像 Boost 这样的库,但我认为当我只想序列化简单变量时,这有点矫枉过正。



已经提前感谢您的回答。 :D

【问题讨论】:

  • 你有什么特别的限制不能使用 boost 吗?魔鬼在细节中,连载就是细节。
  • 听起来你在问这个:C++ FAQ: Serialization and Unserialization(不确定是否需要 boost。标准库中有文件 I/O。)
  • @Scheff 非常感谢您的回答,该网站是我正在寻找的东西,尽管我仍在弄清楚如何将其放入代码中:D
  • 伙计们,我真的不想要 boost 的所有开销,主要是因为我不喜欢它的语法,我真的只想将变量转换为外部二进制文件,是吗nt序列化,还是比我想象的复杂很多

标签: c++ visual-studio serialization c++17


【解决方案1】:

首先,有一点“不一致”:您要求二进制序列化,看起来像一个文本文件。我会假设你真的想要一个二进制输出。

序列化整数时唯一需要注意的是机器的字节序(即使大多数机器都是小字节序)。

在 C++17 或更低版本中,最简单的方法是运行时检查,例如

inline bool littleEndian()
{
    static const uint32_t test = 0x01020304;
    return *((uint8_t *)&test) == 0x04;
}

C++20 引入了编译时检查,因此您可以将之前的代码重写为

constexpr bool littleEndian()
{
    return std::endian::native == std::endian::little;
}

此时您想要的是以标准方式编写所有整数。 通常 BigEndian 是标准。

template <typename T>
inline static T revert(T num)
{
    T res;
    for (std::size_t i = 0; i < sizeof(T); i++)
        ((uint8_t *)&res)[i] = ((uint8_t *)&num)[sizeof(T) - 1 - i];
    return res;
}

此时您的序列化程序将是:

template <typename T>
void serialize(T TestVariable, std::string& FilePath)
{

    static_assert(std::is_integral<T>::value);   //check that T is of {char, int, ...} type
    static_assert(!std::is_reference<T>::value); //check that T is not a reference

    std::ofstream o(FilePath);
    if (littleEndian())
        TestVariable = revert(TestVariable);
    o.write((char *)&TestVariable, sizeof(T));
}

你的反序列化器将是

template <typename T>
void deserialize(T *TestVariable, std::string FilePath)
{
    static_assert(std::is_integral<T>::value);
    std::ifstream i(FilePath);
    i.read((char *)TestVariable, sizeof(T));
    if (littleEndian())
        *TestVariable = revert(*TestVariable);
}

注意:此代码只是一个适用于您的界面的示例,您只需包含&lt;iostream&gt;、&lt;fstream&gt;,如果您使用的是c++20版本,请包含&lt;bit&gt;

【讨论】:

    【解决方案2】:

    首先让我列出不这样做的原因:

    • 在不同的机器上重复使用这些文件是不安全的
    • 速度可能比任何库都慢
    • 指针、映射或结构等复杂类型很难正确实现

    但是如果你真的要做什么定制,你可以简单地使用流,这里是一个使用 stringstream 的例子(我总是在我的单元测试中使用 stringstream,因为我希望它们更快),但你可以简单地将它修改为使用文件流。

    请注意,类型必须是默认可构造的,才能被反序列化模板函数使用。对于复杂的类,这一定是非常严格的要求。

    #include  <sstream>
    #include  <iostream>
    
    template<typename T>
    void serialize(std::ostream& os, const T& value)
    {
        os << value;
    }
    
    template<typename T>
    T deserialize(std::istream& is)
    {
        T value;
        is >> value;
        return value;
    }
    
    int main()
    {
        std::stringstream ss;
        serialize(ss, 1353);
        serialize(ss, std::string("foobar"));
    
        std::cout << deserialize<int>(ss) << " " << deserialize<std::string>(ss) << std::endl;
        return 0;
     }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-04-11
      • 1970-01-01
      • 1970-01-01
      • 2011-01-22
      • 1970-01-01
      • 2013-10-12
      • 2011-05-12
      • 1970-01-01
      相关资源
      最近更新 更多