通过重载运算符 << 和 >> 将结构转换为无符号字符(请参阅更新)

convert struct to unsigned char through overloaded operator << and >> (see update)

我有这个 struct 有 2 个属性(一个 char 和一个 int,用于 3 个字节的内存使用:

struct Node {
    char data;
    int frequency;
}

我尝试为这个 struct 重载运算符 << 和 >>,以便能够使用 fstream 从文件中读取和写入这个 struct 。对于操作员 << 我得到了:

  friend std::ostream& operator<<(std::ostream& output, const HuffmanNode& e) {
    string data = string(1, e.data) + to_string(e.frequency);
    output << data.data();
    return output;
  };

这让人想知道这个 return 有多少 space 到输出(3 个字节,如预期的那样?- 1 个来自 char,2 个来自 int?)

当我想将 struct 保存到文件时,我得到了这个:

List<Node> inOrder = toEncode.inOrder();
for(int i=1; i<=inOrder.size(); i++) {
  output << inOrder.get(i)->getData();

其中列表的每个节点inOrder和上面的树toEncode就是之前列出的structiNOrder.get(i)->getData()return吧。 outputfstream.

现在,我如何从文件中读取数据?使用运算符 >>,我的理解是它需要将一个包含 3 个元素的 unsigned char 数组作为输入,然后将第一个元素(1 个字节)转换为 char,将其他 2 个元素转换为一个诠释。这个对吗?我可以用这个方法做到吗:

  friend std::istream& operator>>(std::istream& input, HuffmanNode& e) {
    ...
  };

或者我需要更改方法签名(和参数)?对于文件读取本身,考虑到我需要读取的字符都在文件的第一行,让程序每次从这一行读取 3 个字符并从中生成 struct 的代码是什么这个数据?

更新

到目前为止我得到了什么:

为了写入文件,我实现了这个运算符<<:

  friend std::ostream& operator<<(std::ostream& output, const HuffmanNode& e) {
    union unsigned_data data;
    data.c = e.data;

    union unsigned_frequency frequency;
    frequency.f = e.frequency;

    output << data.byte << frequency.byte;
    return output;
  };

这样使用:

List<HuffmanNode> inOrder = toEncode.inOrder();
for(int i=1; i<=inOrder.size(); i++)
  output << inOrder.get(i)->getData();

这似乎可行,但如果没有从文件中读取的方法,我无法确定,我得到了这个:

运营商>>:

  friend std::istream& operator>>(std::istream& input, HuffmanNode& e) {
    union unsigned_data data;
    data.c = e.data;

    union unsigned_frequency frequency;
    frequency.f = e.frequency;

    input >> data.byte >> frequency.byte;
    return input;
  };

这样使用:

string line;
getline(input, line);

HuffmanNode node;
stringstream ss(line);
long pos = ss.tellp();
do {
  ss >> node;
  toDecode.insert(node);
  ss.seekp (pos+3);
} while(!ss.eof());

这似乎陷入了无限循环。两个运营商都在使用这个联合:

union unsigned_data {
  char c;
  unsigned char byte;
};

union unsigned_frequency {
  int f;
  unsigned char byte[sizeof(int)];
};

how much space this returns to the output (3 bytes, as expected? - 1 from the char and 2 from the int?)

没有。您正在将值转换为 std::strings,因此它们具有 可变 长度,具体取决于特定值(即 "123" 占用的长度与 "1234567890").您描述的内容适用于值的二进制存储,不适用于值的文本表示

Now, how I do the reading from the file? with the operator >>, what I understand is that it need take an unsigned char array with 3 elements as input, and take the first element (1 byte) and convert to char, and the 2 other elements and convert for an int. Is this correct?

没有。 operator<<operator>> 主要用于 格式化 (文本)I/O。您的 operator<< 实际上是在编写 格式的 输出(不过,您不需要先将值转换为 std::string,您可以将它们写成 as-is 使用 operator<<) 的相关重载。您只需要以 operator>> 可以反转的方式编写格式化数据。例如:

friend std::ostream& operator<<(std::ostream& output, const HuffmanNode& e) {
    output << int(e.data) << ' ' << e.frequency << ' ';
    return output;
}

friend std::istream& operator>>(std::istream& input, HuffmanNode& e) {
    int i;
    input >> i >> e.frequency;
    e.data = char(i);
    input.ignore();
    return input;
}

或者:

friend std::ostream& operator<<(std::ostream& output, const HuffmanNode& e) {
    output << e.data << e.frequency << '\n';
    return output;
}

friend std::istream& operator>>(std::istream& input, HuffmanNode& e) {
    e.data = input.get();
    input >> e.frequency;
    input.ignore();
    return input;
}

格式完全取决于您,具体取决于您的特定需要。

然而,运算符 也可以 也用于 read/write 二进制数据(只要确保在 binary 模式下打开流),例如:

friend std::ostream& operator<<(std::ostream& output, const HuffmanNode& e) {
    output.write(&e.data, sizeof(e.data));
    output.write(reinterpret_cast<const char*>(&e.frequency), sizeof(e.frequency));
    return output;
}

friend std::istream& operator>>(std::istream& input, HuffmanNode& e) {
    input.read(&e.data, sizeof(e.data));
    input.read(reinterpret_cast<char*>(&e.frequency), sizeof(e.frequency));
    return input;
}

这更符合你的想法。