web-dev-qa-db-ja.com

Cでのデータ構造のシリアル化

私は最近、アルゴリズムとデータ構造、TCP/IPソケットプログラミング、およびメモリを使用したプログラミングに関する3つの別々の本を読みました。メモリに関する本では、データ構造をディスクに保存したり、ネットワークを介して送信したりする目的でデータ構造をシリアル化するトピックについて簡単に説明しました。他の2冊の本が連載についてまったく触れていないのはなぜだろう。

Web /ブック検索が失敗した後、Cでのデータ構造のシリアル化に関する優れたブック/ペーパー/チュートリアルがどこにあるのか疑問に思いますか?どこで、どのようにしてそれを学びましたか?

6
Nocturno

Cは構造のシリアル化をネイティブでサポートしていないので、自分で行う必要があります。
一次近似は、(他の返信で述べられているように)プリミティブ型に対して定義し、より大きな構造に再帰的に適用することです。

ただし、単純な概念を超えて対処する必要がある多くの悪魔のような詳細があります。いくつか例を挙げると:

  • 整数のエンディアン順、およびマシンアーキテクチャに応じた一般的なさまざまなタイプの整数のサイズ。シリアライザのすべてのコンシューマが同じバイナリである場合、これはそれほど問題ではありませんが、32ビットPPC 64ビットWindowsマシン上のMacによって生成されたデータの読み取り、または " long」は32ビットまたは64ビットです。
  • 一般的なデータ型のさまざまな表現。 PCではカラービットマップに3つのコンポーネントがありますが、Macでは4つのコンポーネントが異なる順序で
  • 浮動小数点数の表現と精度。
  • 同じ文字の文字列が同一または類似している場合。
  • 循環的または自己参照的なデータ構造を扱う。
12
ddyer

Googleが Protocol Buffers を使って行った作業を見てください。

次のような.protoファイルを記述します。

message Person {
  required int32 id = 1;
  required string name = 2;
  optional string email = 3;
}

次に、プロトコルバッファコンパイラであるprotocを使用してコンパイルし、C++、Java、またはPythonでコードを生成します。

次に、C++を使用している場合は、次のようなコードを使用します。

Person person;
person.set_id(123);
person.set_name("Bob");
person.set_email("[email protected]");

fstream out("person.pb", ios::out | ios::binary | ios::trunc);
person.SerializeToOstream(&out);
out.close();

SerializeToOstreamメソッドを調べると、Googleがシリアル化コードを生成する方法を理解できます。はい、それはC++コードですが、それでもCコードにかなり近いはずです。

7
Robert Harvey

実行可能な速度、使いやすさ、および移植性の間のすべてのさまざまなトレードオフがあり、非常に多くの可能なバリエーションがあるため、おそらくそれはあなたの本では扱われませんでした。

たとえば、1と3はスペクトルの反対側の端であり、2はそれらの間で可能な小さな変動の数を示しています。

  1. シリアライズせず、生のバイトをコピーするだけ

    • これは、アーキテクチャとコンパイラの詳細(エンディアン、パディングとアラインメント、浮動小数点表現)に依存しているため、very移植不可能です
    • (追加の)機能はまったくないため、veryは高速です
    • 間接的な形式を処理しないため、フラットな自己完結型POD構造でのみ機能します
    • デバッグに必要な場合、デコードするのは絶対に面倒です
  2. 1とするが、パディング、配置、エンディアンを明示的に指定する

    • これは現在、移植可能であり、バイトオーダー変換(指定されたものとは異なるネイティブバイトオーダーを持つホスト上)のかなり最小限の追加コスト、および適切なアライメントを強制する要件(すべてのアーキテクチャで最適とは限りません)
  3. すべてをXMLやJSONなどのテキスト形式にシリアル化する

    • これはveryポータブルです
    • およびvery遅い(比較的)
    • 必要に応じて、循環参照を含む間接参照を処理することができます
    • シリアライズされたメッセージを直接読むのは本当に簡単です

ああ、そして私は、既存の文書化されたプロトコルを実装することによって、このこと(上記のすべてに加えて、CORBA、ASN.1、およびProtocolBuffers)について学びました。

主な焦点が速度ではなく携帯性である場合、スペクトルの#3の終わりに向けたものがおそらくより適切です。 howについては、そもそもそれを構築しますが、それはほとんど反射についての問題です。

4
Useless

ウィキペディアの記事 Serialization はトピックをかなりうまくカバーしていますが、奇妙なことに言及していません ASN.1 これは広く嫌われていますが、効率的に説明するための非常によく定義されたよく知られた標準ですデータ直列化プロトコル。 ASNコンパイラは通常、記述されたデータ構造を正規の方法でエンコードおよびデコードするためのコード(Cコードなど)を生成します。

ところで、エンディアンの問題は、Rob Pikeが彼の記事 The Byte Order Fallacy でうまく示したように、Cで簡単に処理できますが、一部のCコンパイラは、常に最適なオブジェクトコードを常に生成するとは限りませんこの手法を使用します。

4
Greg A. Woods