KHPC ver.0.00の内部資料的なもの

  • (by K, 2016.05.19)

基本仕様

  • KHPCの最初のバージョン。KHPCはpersistent-Cの簡易実装を目指したツール群。
  • 基本方針: とにかくできるだけ手抜きをする。次のバージョンでまともにすればいい。手抜きは美徳である。
  • persistent int a; などの「persistent命令」はまだサポートしていない。それはver.0.01で対応する予定。
  • ライブラリ関数があって、それを使えばpersistent命令の代わりはできる。ただし便利ではない。

ダウンロード

関数群

  • void persistent_grp(int grpId, const char *path, const char *tmp, const char *memo);
    • grpIdはセーブファイルに対応した数値。defではセーブファイル名ではなくこの番号でセーブ先を指定する。
    • pathはセーブファイルの名前。
    • tmpは新セーブファイルを作るときの仮の名前。・・・セーブファイルを作っている途中に不意にエラーが起きたら泣けるので、この仮の名前でセーブファイルを作り、完成したところで旧ファイルを消して、pathにリネームしている。
  • void persistent_def(void *p, int size, int grpId, const char *id);
    • pは永続変数へのポインタ。sizeはバイト数。idはgrpId内でユニークな文字列。
  • int persistent_save(double t);
    • 永続変数をセーブする。tは秒数で、指定された秒数よりも頻繁に保存することを防ぐ。
    • t=0なら必ず保存される。
  • int persistent_load(double t);
    • 永続変数をロードする。
  • void persistent_optFlgs(int grpId, const char *id, int flgs);
    • 永続変数の属性のflagsを設定する。未実装。
  • void persistent_optTyp(int grpId, const char *id, const char *typ);
    • 永続変数の属性のtypを設定する。未実装。
  • void persistent_optRem(int grpId, const char *id, const char *rem);
    • 永続変数の属性のremを設定する。未実装。

サンプルコード

#include <stdio.h>
#include <khpc0.h>

int i = 0, sum = 0;
char str[16] = "hello, world";

int main()
{
    persistent_grp(0, "p-vars.pbd", "p-vars.pb_", "@hkawai3.khpc000.test");
    persistent_def(&i,   sizeof(i),   0, "i"  );
    persistent_def(&sum, sizeof(sum), 0, "sum");
    persistent_def(&str, sizeof(str), 0, "str");
    persistent_load(0);
    for (; i <= 100; i++) {
        persistent_save(0);
        sum += i;
    }
    printf("sum=%d\n", sum);
    return 0;
}

// persistent_grpのmemoについて.
//   これは「@hkawai3(人名)のkhpc000というアーカイブの中のtestというプログラム」を意味している.
//   セーブされた変数がどのフォルダに属するものなのかをなんとなく表している.
//   アーカイブ作成者のid的なものから書き始めれば、名前の衝突はない.

メモなど

  • 永続変数は、いずれもなんらかの「グループ」に所属する必要がある。ここで、グループというのはセーブファイルと同義語だと思ってよい。つまり変数ごとに、どのファイルに保存するかを選べる。現状では、1つのプログラム内で設定できるグループは最大で4つ程度を想定している。grpId=0はデフォルトグループであり、特に理由がなければ、このグループに所属させて使うのが好ましい。
    • セーブファイルを複数使えるようにした背景としては、セーブファイル間の変数コピーを容易にしたかったということがある。
    • セーブファイルが別ならば、永続変数idが共通でも、別のものとして扱われる。
  • 永続変数のidとは、変数名、変数の型、変数のサイズなどを反映した文字列である。これが一致しなければ、ロードされることはない。
    • 当面の開発計画におけるデフォルトでは変数名以外の情報が反映されないが、persistent_def関数を直接使えば、より複雑な設定が可能になる。
      • というかver.0.00ではpersistent_defしかないのだけど。
  • persistent_loadを実行すると、それ以降はpersistent_defなどの追加設定はできない。
  • saveに先だって、loadを一度は実行しておかなければならない。
    • loadし忘れを防止するため。loadしないでsaveしたらいつも上書き保存になってしまって、永続変数を使う意味がない。
    • セーブファイルがない状態でloadしても何も起きないだけなので、問題ない。
  • セーブされている変数と、メモリ上の変数とでサイズが違う時の挙動は以下の通り。
    • メモリ上の方が大きい場合: ロード時にはファイルに存在している部分までが読み込まれる。セーブ時には新しい大きなサイズで書き込まれる。
    • ファイル上の方が大きい場合: まずメモリに読み込めるところまで読み込む。次にファイルの残りの部分を読み込んで、それらが全部'\0'であることを確認する。確認した結果'\0'以外があればエラー終了となり、プログラムは停止させられる。
      • つまり末尾ゼロは削られるが、それ以外の場合は削らない。
      • 極力データを失わないようにするため。
      • 将来開発予定のセーブデータ管理ツールを使えば、末尾が'\0'ではなくてもサイズを切り詰められる。
  • flagsの仕様:
    • flagsのどこかのbitが1だと、型情報フィールドが存在する。どこのbitにするかはまだ決めてない。
    • flagsのどこかのbitが1だと、リマークフィールドが存在する。どこのbitにするかはまだ決めてない。

型情報の書き方(案):

  • 基本型はu#,s#,f#,#の4通りしかない。#は10進数の数字。s32なら符号付きの32bit整数。アルファベットなしで数字で始まった場合、用途は不明だがとにかくそのビット数ぶんだけ情報がある(もしくはパディング)。
  • (s32*3:a,u8*4:c)*16は以下の意味になる。
    struct {
      int a[3];
      unsigned char c[4];
    } ???[16];
    • コロンを打てばそのフィールドに名前をつけられる(名前はあってもなくてもいい)。カンマで区切れば連結する。括弧でくくることもできる。掛け算記号で配列を表現できる。|記号を使えばunionも表現できる。
  • 型情報は今のところはリマーク扱いなので、KHPCはこれを感知しない。

既知の問題点

  • エラーが起きた時に、idしか表示していない。grpIdも表示しないとエラーが特定しにくい気がする。

こめんと欄


コメントお名前NameLink

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2016-08-09 (火) 16:24:25 (1018d)