2

クラスオブジェクトを読み取る場合(ここで「arts」はオブジェクトの名前です)。次のコードに従う必要があります。filinは入力ストリームと出力ストリームです。

filin.write((char*)&arts,sizeof(arts));
filin.read((char*)&arts,sizeof(arts));

これらについて説明していただけますか。

  1. なぜ(char *)を追加してカーストと入力するのか、そしてなぜ文字ポインタに追加するのか。

  2. なぜ芸術の前に&シンボルを追加するのですか?

  3. なぜ最後にsizeof(arts)を追加するのですか?

4

5 に答える 5

3

(char *) を追加してカーストを入力する理由と、その理由を文字ポインターに追加する理由.

charは間違った名前です。それは嘘です – それはそれが何であるかだから呼ばれるべきbyteです: a byte . 使用している関数readwrite関数は、バイト バッファーで動作します。これは、それらを汎用にするためです。つまり、任意の型で動作します (これも嘘ですが)。

アートの前に & シンボルを追加するのはなぜですか?

&、オブジェクトのメモリ アドレスを取得します。書き込む(char*) &objことで、特定のオブジェクトの基礎となるバイト バッファ (へのアドレス) を効果的に取得できます。つまり、オブジェクトのバイト単位での表現です。

最後に sizeof(arts) を追加するのはなぜですか?

sizeof(obj)メモリ内のサイズobj、つまり、バイト バッファで占めるバイト数を示します。開始アドレス (前のポイントを参照) とサイズが与えられると、メモリ内のオブジェクトの物理的な存在を完全に特徴付けることができ、これを使用してオブジェクトをメイン メモリからファイルに、またはその逆に転送できます。

しかし、前にも言ったように、それは一種の嘘です。C++ には実際には、この種のメモリのコピーをサポートしていない多くのタイプのオブジェクトがあります。これらのオブジェクトは、実際に存在するメモリについて仮定を行うためです。最も単純なケースでは、ポインタ メンバーが含まれています。オブジェクトは、まだ古い場所を指しているため、もはや役に立ちません:

struct some_class {
    some_class* self;

    some_class() : self(this) { }
};

このクラスには、それ自体を指すメンバー <code>self があります。このクラスのインスタンスをバイトごとにコピーすると、この ID が破棄され、オブジェクトが役に立たなくなります (コピーのselfメンバーをコピーした後、コピーではなくオリジナルを指します)。

この種のバイト単位のコピーは、前述のポインターを正しくコピーするディープコピーとは対照的に、シャロー コピーとも呼ばれます。

あなたが示したコードは、C++ では一般的に安全ではありません。実際、これにはこれまで言及してきたよりもさらに多くの問題があり、ほとんどの場合、オブジェクトの (非) シリアル化のためのより良い代替手段があります。

于 2013-03-14T18:28:34.857 に答える
2

まず、&オペレーターはアート オブジェクトのポインターを取得します。artsあなたのオブジェクトがタイプであると仮定しますFoo

Foo arts;

then&artsはタイプFoo*です。

あなたのコードのメソッドは、バイトwrite()の配列を扱うようです(通常、ネットワーク経由で転送するか、ファイルに書き込むために必要ですcharchar*char、私が知っている任意のプラットフォームで)、したがって、char ポインターを加算または減算すると、そのバイト数だけポインターを進めたり巻き戻したりします (C++ では、ポインター演算はオブジェクトのバイト サイズの倍数のステップで行われます)。 .

Foo*からにキャストするchar*と、オブジェクトのフルサイズの倍数ではなく、そのポインターを1バイトの倍数で扱うようにコンパイラーに効果的に伝えます。write()これは、 and 関数の場合のように、バイト配列を処理する関数の慣例ですread()

最後に、最初のパラメーターで、単純にポインター (メモリー・アドレス) を渡します。そのため、関数write()がポインターから読み取らなければならないバイト数を知るには、オブジェクトの長さ (2 番目のパラメーター) を渡す必要があります。演算子sizeof(arts)は、コンパイル時に、オブジェクトのバイト単位のサイズに変換します(型も取ることができるため、が の型である場合arts、書き込みsizeof Fooは同等です)。Fooarts

于 2013-03-14T18:22:42.893 に答える
2

質問への回答:

1 -ポインターwriteread取得します ( )。これは、バイト単位で動作し、関数の 2 番目の引数で指定されたバイト数とまったく同じ数のバイトを読み書きすることを意味します。charchar *writeread

2-&address of。つまり、 のアドレスを取得し、そのアドレスをとしてポインタartsにキャストしています。char(char*)&arts

3 -パラメータの長さを返します (長さは、メモリ内のインスタンスが占めるサイズsizeof()を指します)。この場合、 のサイズを取得し、および、またはまでのビット数を伝えます。artswritereadwriteread

于 2013-03-14T18:15:20.203 に答える
2

2 番目の質問から始める方が簡単です。演算子 & は、メモリ内のオブジェクトへのポインタを返すだけです。次に、arts オブジェクトへのポインターを char へのポインターにキャストします。Char は、特定のマシンでアドレス指定可能な最小のメモリ ユニットのサイズを持ちます。それは 8 ビット (最も一般的) であり、それ以下でもそれ以上でもかまいません。「バイト」とも呼びます。そして最後に sizeof 関数を呼び出します。これはオブジェクトのサイズを返します。これは、そのオブジェクトを格納するために必要な最小のメモリ ユニット (この場合は chars) の数として表されます。その後、関数はメモリ内のある場所へのポインターと、書き込みまたは読み取りのバイト数を受け取ります。必要なことはすべて知ることです。

于 2013-03-14T18:29:29.313 に答える
1

投稿したコードは、オブジェクトをストリームに保存し、後でストリームから取得します。コードを分割してみましょう。

filin.write((char*)&arts,sizeof(arts));

まず、書き込みメソッドの署名を調べてみましょう。私は、それが次のように見えると思います:

stream::write(char * input, int size)

そのため、ストリーム オブジェクトはメモリ内のある場所へのポインタをsize取得し、そこからバイトを取得して格納します。

それでは、コマンドをこの署名と比較してみましょう。inputは (char*)&arts. あるタイプのartsオブジェクトがあり、それを保存したいとします。inputオブジェクトが格納されているメモリ内に配置するポインタである必要があるため、&演算子を使用して取得します: &arts。ただし、このメソッドは が であると想定しinputていますchar*(つまり、バイトへのポインターではなく、文字を処理する場合だけでなく、バ​​イトを処理する場合にも char が使用されます) が、ポインターは ではありませんchar *。これが、型キャストが作成される理由です。arts型へのポインターは、へのポインターに変換されますchar *。その値は同じままですが、コンパイラーは、自分が何をしているのかを知っていることを知っています。

次に、ストリーム クラスに消費するバイト数を伝える size パラメータがあります。アート オブジェクトを保存したいので、sizeof(arts)そのサイズを確認するために a が呼び出されます。

于 2013-03-14T18:22:52.017 に答える