7

-編集- 文字列ではなくバイナリを送信しています。私のテストでは html ページを使用しているため、この例では文字列のみを使用していますが、私の質問はバイナリ、ベクター、および ostream を使用したデバッグに関するものです。これで混乱が解消されます。

次のコードがあります。

cout << string(&v[0]).substr(0, len);

長さlenを cout にして文字列vを出力するより良い方法はありますか? v[len] = 0 を実行することを考えましたが、サイズ 1 のアサーションがスローされます。私のコードは次のとおりです。

vector<char> v;
v.reserve(1024*16); //required
v.resize(1); //so we can do &v[0]
recv(sockfd, &v[0], v.capacity(), 0);
while (l > 0)
{
    cout << string(&v[0]).substr(0, l);
    recv(sockfd, &v[0], v.capacity(), 0);
}
cout << "the size is " << v.size();
4

4 に答える 4

8

cout オブジェクトでメソッド ostream::write を使用できます。

#include <iostream>
#include <vector>

using namespace std;

int main()
{
  vector<char> test;
  test.push_back('a');
  test.push_back('b');
  test.push_back('c');

  cout.write(&test[0], 3);
  cout << endl;
}

出力:

abc

ostream::write は *this を含む ostream& を返すため、次のこともできます。

cout.write(&test[0], 3) << endl;

しかし、それが実際にそれよりも優れている(またはより明確である)かどうかはわかりません。

于 2009-02-15T17:24:52.550 に答える
6
vector<char> v;
v.reserve(1024*16); //required
v.resize(1); //so we can do &v[0]
recv(sockfd, &v[0], v.capacity(), 0);

そのコードにはバグがあります。呼び出しreserveは、ベクトルへの参照と反復子が再び無効になるまで、少なくともその数の要素を push_back できることを保証するだけです (使用されたバッファーの可能な再割り当てによって)。で行うように、v[0..1024*16-1] に書き込むことはできませrecv。あなたがしなければなりません

v.resize(1024*16); //required

実際に多くの要素を利用可能にし、v.size()代わりに実際に渡しますv.capacity()

あなたの部分文字列操作については、おそらくそうするでしょう

std::string str(&v[0], n);
std::cout << str;

n の範囲は 0 から v.size() までです。std::min(n, v.size())あなたのケースで n が大きくなる可能性があり、上限が必要な場合は、それを保証するために使用できます。

(サイドノードでは、「l」(エル)という変数をそこに置くことは避けます。これは、「1」(1)に非常によく似ているため、人々を混乱させる可能性があるためです)

于 2009-02-15T12:54:42.153 に答える
0

なぜサイズを 1 に設定するのですか?
スペースを予約すると、そのスペースはベクターが (再割り当てなしで) 拡張できるようになります。しかし、直接使用しても安全だと誰が言いましたか? size() がこれらのビットを変更した直後に警告バッファーを追加する (デバッグ) 実装を見たことがありますが、次回チェックしたときにアサートが生成されます。0 -> size() からのみ読み取り/書き込みを行う必要があります。

注: これにより、v[len] = '\0'; も使用できるようになります。

vector<char> v(1024*16);

std::size_t  len = recv(sockfd, &v[0], v.size(), 0);
while (len > 0)
{
    v[len] = '\0';
    cout << &v[0];
    len = recv(sockfd, &v[0], v.size(), 0);
}

これはおそらく文字列を読み取る最良の方法ではないことに注意してください。
ストリームを介して長さ情報を渡すことで、読み取る情報がなくなったときに必要な分だけ読み取ることができます。

于 2009-02-15T17:22:26.393 に答える
-2

コメントを参照してください 。私は知らされていませんでした。しかし、このように内部構造に依存するのは、やはり馬鹿げていると思います。私が最後に使用した Microsoft コンパイラは C99 標準に違反していたので、悲しみは尽きませんでした。vsnprinf()new で正しい戻り値を取得できない場合、本当にこのようなエラータに頼りたいですか?

ベクトルの実装方法に関する仮定を立てています。v[1] がメモリ内の v[0] の直後に来ると想定しています。

char buf[];には違いがあります。& buf[1] == & buf[0] + 1 および ベクトル v; & v[1] == & v[0] + 1 . char 配列はポインター演算を使用します。ベクトルは operator[] を使用します。ベクターがデータを内部に格納する方法は、隣接しているかどうかに関係なく、そのベクター クラスによって異なります。

あなたのコードはまだ動くかもしれませんが、これはまだ悪いことです! それはあなたのソフトウェアをもろくし、予期せぬときに奇妙で予期された方法でソフトウェアを壊してしまいます!

これは、ローカル スタック上の一時的な char 配列にとって理想的な状況です。サイズは小さいです。ハードコーディングされた最大サイズがあります。

サイズが一定でない場合でも、スタック上の小さなローカル文字配列バッファーを使用します。各反復の後、C++ std::string に追加するだけです。(はい、std::strings は複数の null 文字を含むバイナリ値を格納できます。)

recv()は、読み取ったバイト数を返します。ベクトルvは、これを自動的に取得しません。したがって、その値を保存して使用する必要があります。

私は提案します:

#define BUFFER_SIZE  (1024*16)
#define FLAGS        0

int  received = 0;
int  total    = 0;
char buffer [ BUFFER_SIZE + 1 ];

memset( buffer, 0, BUFFER_SIZE + 1 );

received = recv( sockfd, buffer, BUFFER_SIZE, FLAGS );

if ( received > 0 )
{
  copy( buffer + total,
        buffer + total + received,
        ostream_iterator<char>(cout) );

  total += received;
}

while( (received > 0) && (total < BUFFER_SIZE) )
{
  received = recv( sockfd, buffer + total, BUFFER_SIZE - total, FLAGS );

  if ( received > 0 )
  {
    copy( buffer + total,
          buffer + total + received,
          ostream_iterator<char>(cout) );

    total += received;
  }
}

buffer [ total ] = '\0';
buffer [ BUFFER_SIZE ] = '\0';

cout << "The total size is " << total << endl;
于 2009-02-15T17:02:14.647 に答える