C语言和C++从不缺少二进制处理方案,甚至C++有类二进制类 bitset。
当我们想直接操作二进制数据到输入输出流,可能性不大,因为流都被封装了,但这不妨碍我们进行更高抽象的封装。
C 和 C++的二进制流操作 read, write,最小颗粒是 char,字节,8 比特。但C语言提供了位操作,我们可以在此基础上进行每个比特的控制,然后将他们再放进流中,当然,流必须最少是8位的,我们只需要在最后一个压入流的比特进行对齐。
具体的实现是封装两个二进制标准输入和输出类,采用全静态成员及静态函数,可以控制最小一个bit的数据。
一般的用法是通过管道,进行输入输出,如果用标准输出,你可能看到的是乱码。
#include#include #include #include struct BinaryStdIn { //单例模式,不可实体化 BinaryStdIn() = delete; //比特流是否为空 static auto isEmpty() -> bool { return buffer == EOF; } //读取1位数据并返回一个bool值 static auto readBool() -> bool { if (isEmpty()) { throw "Reading form empty input stream"; } N--; bool bit = buffer[N]; if (N == 0) { fillBuffer(); } return bit; } //读取8位数据并返回一个char值 static auto readChar() -> char { if (isEmpty()) { throw "Reading form empty input stream"; } if (N == 8) { auto x = buffer; fillBuffer(); return static_cast (x.to_ulong() & 0xff); } auto x = buffer; x <<= (8 - N); int oldN = N; fillBuffer(); if (isEmpty()) { throw "Reading form empty input stream"; } N = oldN; x |= (buffer >> N); return static_cast (x.to_ulong() & 0xff); } //读取r(1~16)位数据并返回一个char值 static auto readChar(int r) -> char { if (r < 1 || r > 16) { throw std::string("Illegal value of r = ") + std::to_string(r); } if (r == 8) { return readChar(); } char x = 0; for (int i = 0; i != r; ++i) { x <<= 1; bool bit = readBool(); if (bit) { x |= 1; } } return x; } //关闭比特流 static void close() { std::cin.setstate(std::ios::eofbit); } //静态初始化 static void begin() { fillBuffer(); } private: //读流到缓冲区 static void fillBuffer() { if (std::cin.good()) { std::cin.read(reinterpret_cast (&buffer), sizeof(char)); N = 8; } else { // std::cerr << "EOF" << std::endl; buffer = EOF; N = -1; } } //缓冲区 static std::bitset<8> buffer; //缓冲区比特指针 static int N; }; std::bitset<8> BinaryStdIn::buffer; int BinaryStdIn::N; struct BinaryStdOut { BinaryStdOut() = delete; //刷新缓冲流 static void flush() { clearBuffer(); std::cout.flush(); } //写入指定的比特 static void write(bool bit) { writeBit(bit); } //写入指定的8位字符 static void write(char c) { writeByte(c); } static void write(int x) { writeByte((x >> 24) & 0xff); writeByte((x >> 16) & 0xff); writeByte((x >> 8) & 0xff); writeByte((x >> 0) & 0xff); } //写入指定字符的第r(1~16)位 static void write(char c, int r) { if (r == 8) { write(c); } if (r < 1 || r > 16) { throw std::string("Illegal value for r = ") + std::to_string(r); } for (int i = 0; i != r; ++i) { bool bit = ((c >> (r - i - 1)) & 1) == 1; writeBit(bit); } } //关闭比特流 static void close() { std::cout.flush(); } private: static void writeBit(bool bit) { buffer <<= 1; if (bit) { buffer |= 1; } N++; if (N == 8) { clearBuffer(); } } static void writeByte(int x) { assert(x >= 0 && x < 256); char c = static_cast (x); if (N == 0) { std::cout.write(&c, sizeof(char)); return; } for (int i = 0; i != 8; ++i) { bool bit = ((c >> (8 - i - 1)) & 1) == 1; writeBit(bit); } } static void clearBuffer() { if (N == 0) { return; } if (N > 0) { buffer <<= (8 - N); } std::cout.write(reinterpret_cast (&buffer), sizeof(char)); N = 0; buffer = 0; } //缓冲区 static std::bitset<8> buffer; //缓冲区比特指针 static int N; }; std::bitset<8> BinaryStdOut::buffer; int BinaryStdOut::N; void BinaryDump(char *argv[]) { BinaryStdIn::begin(); int width = std::stoi(argv[1]); int cnt = 0; for (cnt = 0; !BinaryStdIn::isEmpty(); ++cnt) { if (width == 0) { continue; } if (cnt != 0 && cnt % width == 0) { std::cout << 'n'; } if (BinaryStdIn::readBool()) { std::cout << '1'; } else { std::cout << '0'; } } std::cout << std::endl; std::cout << cnt << " bits" << std::endl; } auto main(int , char *argv[]) -> int { // BinaryStdIn::begin(); // std::cout << BinaryStdIn::readChar(16) << std::endl; // std::cout << BinaryStdIn::readChar() << std::endl; // std::cout << BinaryStdIn::readBool(); // std::cout << BinaryStdIn::readBool(); // std::cout << BinaryStdIn::readBool(); // std::cout << BinaryStdIn::readBool(); // std::cout << BinaryStdIn::readBool(); // std::cout << BinaryStdIn::readBool(); // std::cout << BinaryStdIn::readBool(); // std::cout << BinaryStdIn::readBool(); BinaryDump(argv); // for (int i = ((48 << 24) + (49 << 16) + (50 << 8) + 51); // i != ((48 << 24) + (49 << 16) + (50 << 8) + 59); ++i) // { // BinaryStdOut::write(i); // } // BinaryStdOut::flush(); return 0; }



