Бинарный аналог std :: dec, std :: hex, std :: oct - PullRequest
0 голосов
/ 15 марта 2019

Я заметил, что хотя стандартная библиотека имеет манипуляторы ввода / вывода для печати чисел в десятичной, шестнадцатеричной или восьмеричной форме (std::dec, std::hex, std::oct), она неесть один для двоичного файла.

Как мне реализовать аналогичный бинарный манипулятор ввода-вывода?


Раздел для предотвращения дублирования: я совершенно разочарован тем, что мне нужно сделатьэто, но мои вопросы почти всегда помечаются как дубликаты совершенно разных и бесполезных вопросов.Возможно, это поможет людям избежать ложных дубликатов и найти настоящие дубликаты, если они существуют.

  • Я знаю, как распечатать двоичное представление числа.Это простая задача для всех, кто знает, как числа хранятся на компьютере, а не цель этого вопроса (т.е. реализация std::string to_binary(T value), void print_binary(T value), ...).
  • Я знаю, что этоЛегко для любого, кто запомнил шестнадцатеричные значения, чтобы преобразовать из шестнадцатеричного в двоичный в своей голове.Но каждый раз, когда вы вводите человеческую работу, вы вводите человеческую способность к ошибке.Всегда лучше избегать этого, если это возможно.
  • Я понимаю, что существуют правила относительно того, что вам разрешено делать в отношении расширения стандартной библиотеки, хотя я недостаточно хорошо знаю внутреннюю работу потоков и манипуляторов, чтобыточно знать, что разрешено в этом случае.Я не ищу ответ «ты не можешь сделать это» - если не удается создать аналог точный , тогда дайте мне самое чистое разрешенное решение, которое вы можете себе представить, разрешенное.

1 Ответ

0 голосов
/ 15 марта 2019

Вот то, что я собрал вместе до сих пор, у него все еще много проблем, и я не очень понимаю, что происходит.Я только что скопировал и изменил решение вопроса Фил.

#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 гораздо шире, чем они должны быть.Я попытался шаблонизировать функцию, и она полностью свела на нет эффект манипулятора, просто распечатав 10 и 11, а не их двоичные представления.

Другая проблема заключается в том, что я не уверен, что лучшеСпособ записи каждого 1 и 0 в поток есть.Пока я пишу их как длинные, что кажется проблематичным, я бы очень хотел написать их как одиночные символы.

Наконец, я не уверен, что new создает утечку памяти, но valgrindговорит мне, что это не так.

...