構造体の直列化(Persistency)

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
雅子鈴木

構造体の直列化(Persistency)

#1

投稿記事 by 雅子鈴木 » 10年前

はじめまして
環境
MS Visual studio 2012 でVC++
シリアライズという言葉を良く耳にしますが、
概念的に理解できないところがあります。

例えば、構造体の中に関数ポインタがあるとします。
仮令同じ関数を指していても、
関数ポインタの設定内容はそのメモリ環境においてのみ有効であって、場によって異なってくると思います。
なので、デシリアライズで復元された関数ポインタで関数を有効にコールする事はできるのでしょうか。
もしできるなら、どうしてできるのでしょうか。

ご存知の方ご教授いただければ幸いです。

beatle
記事: 1281
登録日時: 12年前
住所: 埼玉
連絡を取る:

Re: 構造体の直列化(Persistency)

#2

投稿記事 by beatle » 10年前

関数ポインタにかぎらず、ポインタは基本的にシリアライズ出来ません。
仰るとおり、そのメモリ環境においてのみ有効だからです。

無理やりポインタをアドレスを表す整数値としてシリアライズし、それをデシリアライズしてもでたらめなメモリ位置を指し示すだけで、使い物になりません。

アバター
h2so5
副管理人
記事: 2212
登録日時: 13年前
住所: 東京
連絡を取る:

Re: 構造体の直列化(Persistency)

#3

投稿記事 by h2so5 » 10年前

関数ポインタと文字列を相互変換できるようにしてシリアライズする、という方法もあります。
簡易的ですがこんな感じです。

コード:

#include <stdio.h>
 
typedef void (*FuncPtr)();
#define TABLE_SIZE 2
 
void funcA() {
    puts("funcA called");
}
 
void funcB() {
    puts("funcB called");
}
 
typedef struct {
    char* name;
    FuncPtr func;
} FuncTableItem;
 
// 文字列と関数ポインタの対応テーブル
FuncTableItem table[TABLE_SIZE] = {
  {"funcA", funcA},
  {"funcB", funcB}
};
 
// 文字列から関数ポインタへ変換
FuncPtr name2func(const char *name) {
    int i;
    for (i = 0; i < TABLE_SIZE; ++i) {
        if (strcmp(table[i].name, name) == 0)
            return table[i].func;
    }
    return NULL;
}
 
// 関数ポインタから文字列へ変換
const char* func2name(FuncPtr func) {
    int i;
    for (i = 0; i < TABLE_SIZE; ++i) {
        if (table[i].func == func)
            return table[i].name;
    }
    return NULL;
}
 
typedef struct {
    FuncPtr func;
} Foo;
 
void serialize(char *data, const Foo* foo) {
    sprintf(data, "%s", func2name(foo->func));
}
 
void deserialize(Foo* foo, const char *data) {
    foo->func = name2func(data);
}
 
int main(void) {
    Foo f, f2;
    char data[256] = {0};
    
    // fの内容をシリアライズ
    f.func = funcB;
    serialize(data, &f);
    
    // f2にデシリアライズ
    deserialize(&f2, data);
    f2.func();
    return 0;
}

YuO
記事: 947
登録日時: 13年前
住所: 東京都世田谷区

Re: 構造体の直列化(Persistency)

#4

投稿記事 by YuO » 10年前

シリアライズ時にポインタや関数ポインタ,メンバへのポインタなどを考慮して作れば可能です。
基本的には,オブジェクトや関数,メンバにIDを振っておいて,ポインタの代わりにそのIDを保存します。
非ポインタ,非参照なサブオブジェクトへのポインタも考慮する必要がありますが。
# ポインタ自体がIDといえばIDですが,あくまでシリアライズ時に振り直す必要がある

雅子鈴木

Re: 構造体の直列化(Persistency)

#5

投稿記事 by 雅子鈴木 » 10年前

皆様丁寧なご指導ありがとうございます。
h2so5様がコードまで組んで下さって分かりやすかったのです。

ただ、ポインタの存在はC言語の付き物で、C#やboostあたりでポインタまで
有効にシリアライズしてくれるツールはないでしょうか。

また宜しくお願い致します。

アバター
h2so5
副管理人
記事: 2212
登録日時: 13年前
住所: 東京
連絡を取る:

Re: 構造体の直列化(Persistency)

#6

投稿記事 by h2so5 » 10年前

シリアライズ関連のライブラリとしてはBoost.Serializationなどがあります。
シリアライズ可能な型へのポインタも再帰的にシリアライズできるみたいですね。

YuO
記事: 947
登録日時: 13年前
住所: 東京都世田谷区

Re: 構造体の直列化(Persistency)

#7

投稿記事 by YuO » 10年前

雅子鈴木 さんが書きました:ただ、ポインタの存在はC言語の付き物で、C#やboostあたりでポインタまで
有効にシリアライズしてくれるツールはないでしょうか。
ポインタに限らず,オブジェクトのシリアライズが最終的には自分で実装になるのがC/C++です。
boost::serializerも,ポインタが指す実体のトラッキングはしてくれますが,クラスのシリアライズコード自体は自分で書かないといけません。
ref) http://daily.belltail.jp/?p=345

C#というか.NET Frameworkでは,リフレクション機能があることと,任意の位置へのポインタがないために,
.NET Framework 1.0からBinaryFormatterやXmlSerializerといったシリアライザが用意されています。
他にもDataContractSerializer系のWCF由来のシリアライザやSystem.JsonのようなMS製だけどNuget経由で入れる物,JSON.net等のユーザー製作のシリアライザも存在します。
# オブジェクトグラフのノードを複数回辿らないように注意すれば,独自のシリアライザを書くことも可能ではある。
ただし,C++/CLIでunmanaged pointer使ったり,C#でunsafe pointer使った場合に,シリアライザがまともに動作するかはわかりませんが。

雅子鈴木

Re: 構造体の直列化(Persistency)

#8

投稿記事 by 雅子鈴木 » 10年前

良い勉強になりました!
心よりお礼を申し上げます。

閉鎖

“C言語何でも質問掲示板” へ戻る