2011-11-15 8 views
3

私の現在のプロジェクトでは、メッセージをバイトバッファにシリアライズする必要があるいくつかの異なるインターフェイスがあります。本当のC++プログラマが幸せになれるような方法でやっているのではないかと思います。それは私の頭の上から単なる一例だった、メッセージをシリアル化するC++の方法?

struct MyStruct { 
    uint32_t x; 
    uint64_t y; 
    uint8_t z[80]; 
}; 

uint8_t* serialize(const MyStruct& s) { 
    uint8_t* buffer = new uint8_t[sizeof(s)]; 
    uint8_t* temp = buffer; 
    memcpy(temp, &s.x, sizeof(s.x)); 
    temp += sizeof(s.x); 

    //would also have put in network byte order... 
    ... etc ... 

    return buffer; 
} 

言い訳タイプミス:

は、私は通常、このような何かをするだろう。明らかに、直列化している構造体に内部ポインタがある場合、それはもっと複雑になる可能性があります。私は先のシステムがあることを知っていると仮定すると文字バッファーに直接構造体を鋳造することによりシリアル化して上記

  1. は、特定のシナリオのいずれかの問題があります:

    だから、私は密接に関連している2つの質問を持っています同じエンディアンで?

  2. メイン質問:もっと... erm ... C++?スマートポインタの追加以外にこれを行う方法は?私はこれがSTLがおそらくそれを扱うような共通の問題だと思っています。もしそうでなければ、とにかくC++のメカニズムを使ってやる方が良いでしょう。

EDITボーナスポイントあなたが追加したライブラリせずに、標準C++/STLを使用して、より良い方法でこの構造をシリアル化のクリーンな例を行うことができます。

+0

Googleには[プロトコルバッファ](http://code.google.com/apis/protocolbuffers/docs/overview.html) – Joe

答えて

6

あなたがGoogleのProtocol Buffers(もいるProtobufとして知られている)を見てみたいことがあります。データを言語に依存しないIDLで定義し、ジェネレータで実行してC++クラスを生成します。バイトオーダーの問題を処理し、非常にコンパクトなバイナリ形式を提供することができます。

これを使用すると、C++データを保存することはできませんが、他の言語(C#、Java、Pythonなど)でも使用できるようになります。

+1

+1これは興味深いので - しかし、ネイティブC + +ストリーム/ STLできれいにそれを行う答えを追加することができますライブラリを追加するための承認プロセスはかなり難しいです:( –

6

Boost :: serializationまたはストリームを直接使用する必要があります。右のいずれかのリンクに詳細があります。

Is it possible to serialize and deserialize a class in C++?

+1

+1があります。これは面白そうだからですが、あなたがきちんと答えることができれば( –

+0

)私はちょうど私がそれをする答えを追加しましたが、私は "リンク右に "私はここでそれを再現しないと多くの情報を持っていた:) – AzP

1

答えとしてAzPsが答えました。ブーストをチェックすると、最初に行く方法です。あなたのコードのサンプルについてのほかに

- ファイルを取る方法にあなたのシリアライズ関数のシグネチャを変更する:

void MyStruct::serialize(FILE* file) // or stream 
{ 
    int size = sizeof(this); 
    fwrite(&size, sizeof(int), 1, file); // write size 
    fwrite(this, 1, size, file);   // write raw bytes of struct 
} 

は、構造体をコピーする必要性を低減します。

- はい、あなたのコードは、プラットフォーム、コンパイラ、コンパイラの設定に応じてシリアル化されたバイトを作成します。これは良くないか悪いです。同じバイナリがシリアライズされたバイトを書き込み読み込む場合、シンプルさとパフォーマンスのために単調かもしれません。しかし、エンディアンだけでなく、パッキングや構造体レイアウトも互換性に影響します。例えば、32ビット版や64ビット版のアプリケーションでは、私たちの構造体のレイアウトが確実に変更されます。最後に生のフットプリントをシリアル化することで、パディングバイト - コンパイラが構造体フィールドの間に置く可能性のあるバイト数、トラフィックの多いネットワークストリームに望ましくないオーバーヘッドがシリアライズされます。

編集:

「埋め込み」が追加されています。はい、そのような単純なシリアライズ/デシリアライズ(上記のシリアライズのミラー実装)メソッドは良いと簡単な選択かもしれません。

+0

+1、ありがとう:) –

+0

stdioの 'FILE'ポインタはC + +のシリアル化の方法ですか?私はあなたがコメントでストリームを言及したことを知っているが、それはコメントに含まれていませんが、コードに!それ以外の場合は、ファイルまたはストリームを関数に渡すという考え方は、もちろん、各関数呼び出しで新しいバッファを割り当てるよりも良い考えです。 –

+0

まあ、私はあなたのポイントを得る。 C++の方法はstd :: ostream、yesになります。しかし、特にstd :: streamライブラリにはしばしば驚きがあり、生のc API、特にかなりプラットフォームに依存しないファイルapiには何も間違っていません。ここでは、std :: streamを避けるために、ライブラリの内部バッファリングとフラッシュについて考えないようにします。実際にはファイル内に構造体を保存していて、std :: streamの内部構造がわからないのであれば、未処理のファイルは単に実用的でシンプルで確かにstd :: streamより高速です。 – citykid

関連する問題