2013-09-08 6 views
2

Я знаю, что в C++ мы можем форматировать вывод/ввод с использованием флагов состояния, таких как ios :: showbase ... Я знаю, что мы можем установить флаг для basefield в hex, oct, dec, но есть ли bin? и как форматировать целые числа в бинарном базовом поле?Как форматировать флаги в C++?

+0

Да, извините, неправильно понято – Itay

+0

Не беспокойтесь! Я приветствую любые комментарии – ProDev7

ответ

7

Вы можете использовать bitset<>. Например:

int x = 1025; 
    std::cout << std::bitset<32>(x) << std::endl; 

выше будет производить вывод:

00000000000000000000010000000001 
+0

Спасибо, что сработали! – ProDev7

+0

Наконец-то вы могли бы объяснить, почему нет ios :: bin? – ProDev7

+3

Стандарт C++ не предусматривает его. Я не думаю, что было бы разумно рассуждать о том, почему. – jxh

1

Я понимаю, что многие люди довольны подходом, используя std::bitset<N> для печати соответствующего значения. Несмотря на такую ​​работу, я хотел бы отметить, что это можно написать манипулятор bin, хотя он немного связан с вами: вы должны были бы получить от std::num_put<char> и установить std::locale с использованием соответствующего фасета. Ниже приведена реализация этого подхода. Посмотрите на функцию print() внизу, чтобы увидеть «хороший» код - вершина просто заставляет вещи произойти с фасеткой std::nun_put<char>.

#include <iostream> 
#include <iomanip> 
#include <locale> 
#include <limits> 
#include <iterator> 
#include <algorithm> 

int bin_index(std::ios_base::xalloc()); 

struct num_put 
    : std::num_put<char> 
{ 
public: 
    num_put(std::locale const& chain) 
     : d_chain(std::use_facet<std::num_put<char> >(chain)) { 
    } 
private: 
#if __cplusplus == 201103L 
    typedef long long   long_forward; 
    typedef unsigned long long actual_type; 
#else 
    typedef unsigned long long_forward; 
    typedef unsigned long actual_type; 
#endif 

    std::num_put<char> const& d_chain; 
    typedef std::num_put<char>::iter_type iter_type; 
    iter_type do_put(iter_type to, std::ios_base& fmt, char_type fill, 
        long v) const { 
     return fmt.iword(bin_index) 
      ? this->put(to, fmt, fill, static_cast<long_forward>(v)) 
      : this->d_chain.put(to, fmt, fill, v); 
    } 
#if __cplusplus == 201103L 
    iter_type do_put(iter_type to, std::ios_base& fmt, char_type fill, 
        long long v) const { 
     return fmt.iword(bin_index) 
      ? this->put(to, fmt, fill, static_cast<unsigned long long>(v)) 
      : this->d_chain.put(to, fmt, fill, v); 
    } 
    iter_type do_put(iter_type to, std::ios_base& fmt, char_type fill, 
        unsigned long v) const { 
     return fmt.iword(bin_index) 
      ? this->put(to, fmt, fill, static_cast<unsigned long long>(v)) 
      : this->d_chain.put(to, fmt, fill, v); 
    } 
#endif 
    iter_type do_put(iter_type to, std::ios_base& fmt, char_type fill, 
        actual_type v) const { 
     if (fmt.iword(bin_index)) { 
      char bits[std::numeric_limits<actual_type>::digits]; 
      char* end(bits); 
      if (v == 0) { 
       *end++ = '0'; 
      } 
      else { 
       for (; v; ++end) { 
        *end = "01"[v & 0x1u]; 
        v >>= 1; 
       } 
      } 
      std::streamsize show(2 * (bool(fmt.flags() 
              & std::ios_base::showbase))); 
      std::streamsize nofill(show + end - bits < fmt.width() 
            ? fmt.width() - (show + end - bits) 
            : 0); 
      fmt.width(0); 
      if (0 < nofill && (fmt.flags() & std::ios_base::right)) { 
       end = std::fill_n(end, nofill, fill); 
      } 
      if (fmt.flags() & std::ios_base::showbase) { 
       *end++ = 'b'; 
       *end++ = '0'; 
      } 
      if (0 < nofill && (fmt.flags() & std::ios_base::internal)) { 
       end = std::fill_n(end, nofill, fill); 
      } 
      to = std::copy(std::reverse_iterator<char*>(end), 
          std::reverse_iterator<char*>(bits), 
          to); 
      if (0 < nofill && (fmt.flags() & std::ios_base::left)) { 
       to = std::fill_n(to, nofill, fill); 
      } 
      return to; 
     } 
     else { 
      return this->d_chain.put(to, fmt, fill, v); 
     } 
    } 
}; 

std::ostream& bin(std::ostream& out) 
{ 
    if (!dynamic_cast<num_put const*>(
      &std::use_facet<std::num_put<char> >(out.getloc()))) { 
     std::locale loc(std::locale(), new num_put(out.getloc())); 
     out.imbue(loc); 
    } 
    out.iword(bin_index) = true; 
    return out; 
} 

std::ostream& nobin(std::ostream& out) 
{ 
    out.iword(bin_index) = false; 
    return out; 
} 

void print(int value) 
{ 
    std::cout << std::right; 
    std::cout << nobin << std::setw(8) << value << "=" 
       << bin << std::right << std::setw(20) << value << "'\n"; 
    std::cout << nobin << std::setw(8) << value << "=" 
       << bin << std::internal << std::setw(20) << value << "'\n"; 
    std::cout << nobin << std::setw(8) << value << "=" 
       << bin << std::left << std::setw(20) << value << "'\n"; 
} 

int main() 
{ 
    std::cout << std::showbase; 
    print(0); 
    print(17); 
    print(123456); 
} 
+0

когда я скомпилирую этот код, я получил 20 компиляционных эров; из них: ошибка C2632: «long», а затем «long» является незаконной – ProDev7

+0

@ ProDev7: Кажется, вы не используете C++ 11! В этом случае вещи должны быть структурированы несколько иначе. Я обновлю ответ, как только у меня будет версия, выполняющая оба ... –

+0

@ ProDev7: Я обновил код для компиляции как с C++ 03, так и с C++ 11 и использовал соответствующие перезаписанные версии 'do_put () '(Я думаю, он не слишком тщательно проверен). –