【问题标题】:Binary analog of std::dec, std::hex, std::octstd::dec、std::hex、std::oct 的二进制模拟
【发布时间】:2019-03-15 01:12:32
【问题描述】:

我注意到虽然标准库有 I/O 操纵器来打印十进制、十六进制或八进制形式的数字 (std::dec, std::hex, std::oct),但它没有用于二进制的。

我将如何实现一个类似的二进制 I/O 操纵器?


反重复标记部分:我很失望我必须这样做,但我的问题几乎总是被标记为完全不同且无用的问题的重复。也许这将帮助人们远离虚假重复并找到真正的重复(如果确实存在)。

  • 我知道如何打印数字的二进制表示。对于任何知道数字如何存储在计算机中的人来说,这是一项微不足道的任务,而不是这个问题的目的(即实现std::string to_binary(T value)void print_binary(T value),...)。
  • 我知道任何记住十六进制值的人都可以很容易地在头脑中从十六进制转换为二进制。但是任何时候你引入人类工作,你就引入了人类犯错的能力。如果可能,最好尽量避免。
  • 我意识到在扩展标准库方面允许您做什么是有规则的,尽管我不太了解流和操纵器的内部工作原理,无法确切知道在这种情况下允许做什么。我不是在寻找一个“你不能那样做”的逃避答案 - 如果无法创建 exact 模拟,那么给我你能想到的最干净的允许解决方案是允许。

【问题讨论】:

  • 绝对看起来像一个起点。我现在正在从那里开始工作,但从那里到这里绝对是一个不平凡的扩展。
  • 我认为bitset 绝对是一个合理的考虑,因为我目前的方法是多么的老套。我看到的唯一问题是他们使用硬编码大小对其进行模板化,希望这不是必需的。
  • 确认的硬编码大小对于bitset不是必需的,可以使用8 * sizeof(var)进行模板化。

标签: c++ iostream


【解决方案1】:

这是我到目前为止汇总的内容,它仍然有很多问题,我真的不明白发生了什么。我刚刚复制并修改了questionPhil 链接的解决方案。

#include <ios>
#include <iostream>
#include <locale>

int geti() { 
    static int i = std::ios_base::xalloc();
    return i;
}

std::ostream& bin_manip(std::ostream& os) {
  os.iword(geti()) = 1;
  return os;
}

std::ostream& dec_manip(std::ostream& os) {
  os.iword(geti()) = 0; 
  return os;
}

struct my_num_put : std::num_put<char> {
  iter_type do_put(iter_type out, std::ios_base& str, char_type fill, long v) const {
    bool binary_flag = str.iword(geti());
    if (binary_flag) {
      size_t width = 8 * sizeof(v);
      for (size_t i = width - 1; i < width; --i) {
        long bit = (((1 << i) & v) >> i) & 1;
        out = std::num_put<char>::do_put(out, str, fill, bit);
      }
      return out;
    }
    else {
      return std::num_put<char>::do_put(out, str, fill, v);
    }
  } 

  /*
  iter_type do_put(iter_type s, std::ios_base& f, char_type fill, unsigned long v) const { 
    return std::num_put<char>::do_put(s, f, fill, v + f.iword(geti())); 
  }
  */ 
};

int main() {
  std::cout.imbue(std::locale(std::locale(), new my_num_put));  // memory leak?
  int v1 = 10;
  long v2 = 11;
  std::cout << bin_manip << v1 << std::endl << v2 << std::endl;
  std::cout << dec_manip << v1 << std::endl << v2 << std::endl;

  return 0;
}

输出如下:

0000000000000000000000000000000000000000000000000000000000001010
0000000000000000000000000000000000000000000000000000000000001011
10
11

我在这里看到的主要问题是处理各种类型时的代码重复。照原样,我刚刚使用了do_put 函数,该函数采用long 类型的值,不幸的是,它打印出的int 值比它们应该的要宽得多。我尝试对函数进行模板化,它完全取消了操纵器的效果,只是打印出 1011 而不是它们的二进制表示。

另一个问题是我不确定将每个10 写入流的最佳方法是什么。现在我把它们写成 long 似乎有问题,我真的很想把它们写成单个字符。

最后,我不确定new 是否会造成内存泄漏,但 valgrind 告诉我不会。

【讨论】:

  • 避免泄漏的常用方法是将static my_num_put singleton;添加到类中,然后使用&amp;my_num_put::singleton而不是new my_num_put——创建构面的单个静态实例并(重新)使用根据需要经常这样做,因为它不包含任何状态。
猜你喜欢
  • 1970-01-01
  • 2015-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多