読者です 読者をやめる 読者になる 読者になる

音の鳴るブログ

鳴らないこともある

CのコードをJavaScriptにコピペする

最近CのコードをコピペしてJavaScriptにするのが流行っている。大体はコピペした後、型の情報をなくしてアロー演算子をドット演算子に置換すればOKなのだけど、いくつか頑張る必要がある。できるだけ元のコードに手を加えずに利用するための簡単なメモ。

このやり方を実践したやつ : liboggJavaScript化

大まかな手順

  1. 関数の定義だけ書き写す. 中身は throw new Error("not implemented"); だけ
  2. テストコードやサンプルコードを移植する
  3. 実行すると "not implemented" のエラーがでる
  4. 未定義の関数をコピペする (関数1つ分だけ作業する)
  5. 実行すると "not implemented" のエラーがでる
  6. 未定義の関数をコピペする (関数1つ分だけ作業する)
  7. 繰り返し..

コンパイル

  1. grunt-contrib-concatでファイルを結合する

構文チェック

  1. grunt-contrib-jshint でやる
  2. もとのCのコードにあわせてオプションを設定する (curly:falseとか)
  3. eqeqeq:true は有効のままで、コードの方を書き換えた方が良い

構造体

  1. 構造体の代わりにオブジェクトを使う
  2. memsetでゼロクリアとかはできないので、それ用の関数を作る
  3. オブジェクトは構造体のポインタの扱いになる
  4. アロー演算子はドット演算子に置換
typedef struct {
  int a;
  int b;
} hoge_t;

hoge_t* hoge = malloc(sizeof(*hoge));
memset(hoge, 0, sizeof(*hoge));
hoge->a = 10;
function hoge_t(p) {
  p = p||{};

  // このあたりに元の定義をコピペしてコメントアウトしておくと便利

  p.a = 0;
  p.b = 0;
  p.__name = "hoge_t"; // デバッグ用

  return p;
}

var hoge = hoge_t();
hoge_t(hoge);
hoge.a = 10;

ポインタ

  1. 数値型のポインタの場合は TypedArray で代用する
  2. ポインタ操作関数を作る
  3. ポインタの加減算は見逃してはならない
int* a = malloc(10 * sizeof(int));
int* b = a+5;

b[0] = 10;

printf("a[5]=%d\n", a[5]); // 10
function pointer(src, offset, length) {
  offset = src.byteOffset + offset * src.BYTE_PER_ELEMENT;
  if (typeof length === "number") {
    return new src.constructor(src.buffer, offset, length);
  } else {
    return new src.constructor(src.buffer, offset);
  }
}

var a = new Int16Array(10);
var b = pointer(a, 5) // a+5 とすると文字列になるので注意

b[0] = 10;

console.log("a[5]=%d", a[5]); // 10

malloc/free

  1. 数値型のポインタの場合は TypedArray で代用する
  2. 他は Array で代用する
int* a = malloc(64 * sizeof(int));
hoge_t* hoge = malloc(16 * sizeof(hoge_t));

a[0] = hoge[0].a = 10;

free(a);
free(hoge);
var uint8 = 0, int16 = 1;

function calloc(n, type) {
  switch (type) {
    case uint8: return new Uint8Array(n);
    case int16: return new Int16Array(n);
  }
  var a = new Array(n);
  for (var i = 0; i < n; i++) {
    a[i] = type();
  }
  return a;
}

var a = calloc(64, int16);
var hoge = calloc(16, hoge_t);

a[0] = hoge[0].a = 10;

a = null;
hoge = null;

memcpy (memmove)

  1. できないので似た感じ関数で代用する
int* a = malloc(100, sizeof(int));
memmove(a + 5, a + 10, 2*sizeof(int));
function copy(dst, src, offset) {
  dst.set(src, offset||0);
}

var a = calloc(100, int16);
copy(a, a.subarray(10, 10+2), 5); // ちょっと慣れが必要

その他

  1. ビットシフトは雑だけど、右シフト (>>) は論理シフト (>>>) に置換
  2. 文字列は String.fromCharCode とかを使って、頑張って文字列に変換する
  3. 名前空間は工夫する ()
  4. goto文はこの記事を参考にループ化する. javascriptでgotoを実装する方法