0

あるファイルから別のファイルにビットごとに情報を書き込む関数のテスターを作成しようとしています。以下のコードは期待どおりに「A」を出力するため、BitOutputStream クラスが機能することは間違いありません。しかし、入力ファイルを取得して出力ファイルを書き込む以下の 2 番目のバージョンにコードを変更すると、入力が出力と一致しません。うっかり変更してはいけないものを変更してしまったのか、それとも入力ファイルに特定の「隠し」文字が含まれていて、不一致やバイト シフトが発生したのかはわかりません。get() を正しく使用していないのではないかと思います。どんな助けでも大歓迎です。

/* 最初の (作業中の) バージョン */

int main(int argc, char* argv[])
{
  BitOutputStream bos(std::cout);  // channel output to stdout
  bos.writeBit(1);
  bos.writeBit(0);
  bos.writeBit(0);
  bos.writeBit(0);
  bos.writeBit(0);
  bos.writeBit(0);
  bos.writeBit(0);
  bos.writeBit(1);

  // prints an 'A' as expected

  return 0;
}

/* 2 番目の (非稼働) バージョン */

int main(int argc, char* argv[])
{
  std::string ifileName = std::string(argv[1]);
  std::string ofileName = std::string(argv[2]);

  ofstream ofile;
  ifstream ifile;

  if(ifile)
    ifile.open(ifileName, ios::binary);
  if(ofile)
    ofile.open(ofileName, ios::binary);

  BitOutputStream bos(ofile);

  int i;
  while (ifile.good()) { 
    i = bos.writeBit(ifile.get()); // could the error be due to incorrect usage of get()?
    std::cout << i << std::endl;  // just to see how many bits have been processed
  }

    bos.flush();

    ifile.close();
    ofile.close();

    return i;
 }

私が呼び出す最初のバージョン

./a.out

私が呼び出す2番目のバージョン

./a.out input output

これは 1 2 3 を端末表示に出力します writeBit は 3 回呼び出されましたが、'A' に対して 8 回呼び出されると予想していたのに、なぜ 3 回しか呼び出されないのですか?

入力ファイルには「A」だけが含まれています。入力ファイルで hexdump を呼び出すと、次が生成されます。

0000000 0a41
0000002

出力ファイルで hexdump を呼び出すと、次が生成されます。

0000000 0005
0000001

また、hexdump が 0a-'linefeed' と 41-'A' の前に 7 つの 0 を生成するのはなぜですか? また、最後の '0000002' の意味は何ですか? 入力と出力の 16 進ダンプが一致するように、コードの 2 番目のバージョンで何を変更できますか?

編集: BitOutputStream の宣言/定義は次のとおりです。

#ifndef BITOUTPUTSTREAM_HPP
#define BITOUTPUTSTREAM_HPP
#include <iostream>

class BitOutputStream {

private: 
  char buf;             // one byte buffer of bits
  int nbits;            // how many bits have been written to buf
  std::ostream& out;    // reference to the output stream to use

public:
  /* Initialize a BitOutputStream that will 
   * use the given ostream for output. 
   * */
  BitOutputStream(std::ostream& os) : out(os) {
    buf = nbits = 0;    // clear buffer and bit counter
  }

  /* Send the buffer to the output, and clear it */
  void flush() {
  out.put(buf);
  buf = nbits = 0;
  }


  /* Write the least sig bit of arg into buffer */
  int writeBit(int i) {
  // If bit buffer is full, flush it.
  if (nbits == 8) 
    flush();

  int lb = i & 1;      // extract the lowest bit
  buf |= lb << nbits;  // shift it nbits and put in in buf

  // increment index
  nbits++;

  return nbits;
  }
};

#endif // BITOUTPUTSTREAM_HPP
4

1 に答える 1

1

問題は、ビット対バイトの概念です。ほとんどの関数が使用するバイトは、ビットの集まりです。ファイルはバイト単位で読み取られます。メソッドwriteBitは、バイトではなくビットを書き込みます。

本当に本当にビットで書き込む必要がある場合は、バイトで読み取り、ビットに変換して各ビットを書き込む必要があります。(ちなみに、ほとんどのコンピューターは、バイトやワードなどのより大きな単位でうまく機能します。)

#include <cstdint>
#include <iostream>

using namespace std; // Because I'm lazy and this is an example.

int main(void)
{
    uint8_t byte;
// Open the file
//....

//  Read file as bytes.
    while (ifile.read(&byte, sizeof(byte)))
    {
        for (unsigned int i = 0;
             i < CHAR_BIT; // number of bits in a byte
             ++i)
        {
            bos.writeBit(byte & 1);
            byte = byte >> 1;
        }
    }
//...
    return EXIT_SUCCESS;
}  

あるファイルの内容を別のファイルにコピーするより高速な方法があります。最初に頭に浮かぶのは、OSに任せることです。

編集 1: プログラムの分析。クラスは、メソッドに渡された整数
BitOutputStream最下位ビットを累積します。writeBit8 ビットが蓄積されるとすぐに、writeBitメソッドは 1 バイトを出力ストリームに書き込みます。

最初のプログラムでは、有効ビットが 1 つしかない整数を渡しているか、整数定数の有効ビットが 1 つだけであると想定しています。

2 番目のプログラムでは、メソッドを介して 1 バイト (8 ビット) を読み込みますistream::get()。このwriteBitメソッドは、最下位ビットのみを見て、そのビットをBitOutputStreamバッファーに入れます。次に、ループは入力ファイルから別のバイトをフェッチし、最下位ビットのみがBitOutputStreamバッファーに追加されます。

8 番目のバイトが読み取られると、BitOutputStreamバッファーは 8 ビットになり、8 ビットのバイトがストリームに書き込まれます。

したがって、「A」文字のみのファイル (0x41、またはバイナリ MSB: 0100 0001 ) がある場合、
このwriteBitメソッドは値と 0x1 の AND をとり、結果は 0x01 またはバイナリ 1 になります。このビットは、出力バッファ。 バイトの残りのビットは によって無視されwriteBitます。

1文字しかない場合、BitOutputStreamバッファは1ビットしかありません。また、プログラムは呼び出しを行わないBitOutputStream::flush()ため、部分ビットがストリームに出力されることはありません。bosデストラクタがないため、オブジェクトが破棄され、出力ストリームに何も書き込まれない 場合、不完全なバイト (1 ビットのみ) は消えます。

2 番目のプログラムは 8 ビットのバイト全体を 1 ビットのみを使用する関数に渡すため、ビットとバイトの概念を混同していると推測しました。問題を解決する上記のコード フラグメントを参照してください。

編集 2:BitOutputStreamクラスのテスト。
このクラスをテストするための最良のプロセスは、 から独自のクラスを派生させることostreamです。このクラスには、期待値または既知の値を渡すことができるメソッドが必要です。このクラスのインスタンスを に渡しますBitOutputStream。クラスのメソッドは、値を期待値または既知putの値と比較できます。BitOutputStream

于 2013-08-24T17:27:34.303 に答える