すべての変数は、コンピューターのメモリに存在します。メモリはバイト単位で編成されます。
C++ コードを書いているときは、これらのバイトを直接読み取ることができます。構造体の場合、そのすべてのメンバーのメモリは 1 つの連続したチャンクにあります (ただし、各メンバー間にギャップがある場合があります)。
だから、私が宣言した場合:
struct foo {
char x;
char y;
short z;
int q;
};
次に、を作成するstruct foo
と、次のレイアウトがメモリに取得されます (ほとんどのシステムでは合計 8 バイト)。
xyzzqqqq
最初のバイトはx
、2 番目y
、3 番目、4 番目のバイトを合わせてz
、最後の 4バイトはq
です。
したがって、オブジェクトはすでに「シリアル化」されています-それを表す一連のバイトがあります。ネットワーク経由で送信する必要があるのは、データ構造を表す情報だけです。
独自のシリアライザーを作成する理由は、オブジェクトの読み取りまたは書き込みの方法を変更したい場合があるためです(たとえば、フィールドを追加した場合はどうなるstruct foo
でしょうか?)。メモリ レイアウトが異なるマシン間で通信する必要があるためです。が異なる (のどのバイトがz
数値の「最も重要な」部分を表すか?)、または構造の一部のみをシリアル化したいため (メンバー間に空のスペースがある場合はどうなるでしょうか?)。
しかし、基本的に、「char データ」を送信する理由は、コンピューター内のすべてをそのように表現できるからです。シンボル エンコーディングに関するチューリングの証明には立ち入りませんが、あらゆる知識を一連の 1 と 0 としてエンコードできることは数学的に証明されています。
より具体的に言えば、データをパケットの「char data」フィールドに入れる方法はmemcpy
、データが現在ある場所からバッファに入れることです。したがって、 があった場合、次のようchar* target
に a を書き込むことができstruct foo x
ます。
memcpy(target, &x, sizeof(struct foo));
または、各フィールドを記述して、より慎重に行うこともできます。
memcpy(target, &x.x, 1);
memcpy(target+1, &x.y, 1);
memcpy(target+2, &x.z, sizeof(short));
memcpy(target+4, &x.q, sizeof(int));
&
まだ知らなかった場合は、これがアドレス取得演算子です。したがって、各メンバーのアドレスから 内のオフセットにtarget
書き込み、メンバー変数表現の長さに等しいバイト数を書き込みます。
最後の質問に対する受け入れられた回答は、これが単純化しすぎていることを指摘していました。ネットワーク経由でマルチバイト整数を送信する場合、エンディアン(バイト順) について心配する必要があります。したがって、実際に行うことは次のとおりです。
memcpy(target, &x.x, 1);
memcpy(target+1, &x.y, 1);
*((short*)(target+2)) = htons(x.z);
*((int*)(target+4)) = htonl(x.q);
これは、ホスト バイト オーダーからネットワーク バイトオーダーに変換するために、必要に応じてバイトの反転を処理します。明らかに、1 バイト長の値は影響を受けません。