setjmp/longjmpによるメモリリークパターン

setjmp/longjmpによるメモリリークパターンを紹介します。
次のコードを見てください。

main.c

#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>

jmp_buf env;

void sub(void)
{
  longjmp(env, 1);
}

int main(int argc, char** argv)
{

  char* buf1 = NULL;
  char* buf2 = NULL;

  buf1 = (char*)malloc(100);
  printf("1:buf1 = %p\n", buf1);

  if(setjmp(env)){
    printf("3:buf1 = %p\n", buf1);
    printf("4:buf2 = %p\n", buf2);
    free(buf1);
    free(buf2);
    return 0;
  }

  buf2 = (char*)malloc(200);
  printf("2:buf2 = %p\n", buf2);

  sub();

  return 0;
}

開始直後に確保したメモリをbuf1に、setjmp後に確保したメモリをbuf2に結び付けています。
その後sub()呼び出しによりlongjmpが行われ、遷移先(setjmp戻り真の場合の処理)で各メモリを解放する、というものです。
このコードをUbuntu Linux (x86)上でコンパイルし、実行すると

$ gcc main.c -O0
$ ./a.out 
1:buf1 = 0x83a9008
2:buf2 = 0x83a9070
3:buf1 = 0x83a9008
4:buf2 = 0x83a9070
$ 

となります。特に問題なく、メモリ解放できていそうです。
しかし、これを最適化ありでコンパイルすると、

$ gcc main.c -O2
$ ./a.out 
1:buf1 = 0x8170008
2:buf2 = 0x8170070
3:buf1 = 0x8170008
4:buf2 = (nil)
$

となります。
buf2がNULLになっているため、buf2の解放ができていません。
理由は、最適化されていない場合、buf1、buf2はスタックポインタ(レジスタ)が”指し示す”スタック上の1データにすぎないため、setjmpコール時点もlongjm後も変化しない。しかし、最適化が行われると、このコードの場合、buf1やbuf2そのものがレジスタに割り当てられようです。setjmpでコール時点でのそのレジスタ状態(buf2はNULLだという状態)が保持され、longjmpで遷移した時にsetjmpで保持されたもの(buf2はNULLだという状態)がレジスタとして復元されるためです。

http://linuxjm.sourceforge.jp/html/LDP_man-pages/man3/longjmp.3.html
に、

以下の条件が全て成立する場合、 longjmp() の呼び出しが行われた後の自動変数の値は未定義 (unspecified) となる。

  • その自動変数が、対応する setjmp(3) 呼び出しを行った関数のローカル変数である。
  • 自動変数の値が setjmp(3) と longjmp() の間で変更されている。
  • volatile として宣言されていない。

とあります。
また、

    longjmp() や siglongjmp() を使うと、プログラムは理解しづらく、保守しにくいものになる。別の方法が可能なら、それを使うべきである。

また、setjmpのほうにも

    setjmp() や sigsetjmp() を使うと、プログラムは理解しづらく、保守しにくいものになる。別の方法が可能なら、それを使うべきである。

と記載があります。

setjmp/longjmpの利用には細心の注意が必要です。

Macでファイル名が文字化けしてファイルが削除できない

知人が作成したZIPファイルをMac上で、unzipしたところ、本来日本語になるべきところが、%EA%EC…みたいな感じで化けてしまいました。

気持ちが悪いので早速削除しようとしたのですが、削除できませんでした。

「予期しないエラーが起きたため、操作を完了できません(エラーコード -8072)。」

とメッセージされるのです。
エラーメッセージを検索すれば解決するか、、、と楽観していましたが、的確な回答が全く見当たらず、焦りました。

最終的に、ひらめいたことがあり、試してみました。異なるファイルシステム間のファイル転送を使命とされているFTPのクライアントソフトならこのへんうまく削除してくれるのでは、と。

早速、普段使用しているFTPクライアントFileZillaを起動し、問題となっているファイルを削除してみました。すると見事削除されました。しかし、念のため、Finderから見てみると、なぜかまだありました。一瞬焦りましたが、キャッシュが効いているのでは、と思い、Finderを一度終了させてから、再度起動して確認しました。
結果、しっかり削除されていました。

同じ目に会って、この記事にたどり着いた方は、ぜひ試して、結果をコメントしていただけるとありがたいです。

Unityで2Dゲーム開発(8)〜OTSpriteの現フレーム画像オリジナルサイズ取得方法〜

OTSpriteの任意フレームを拡大あるいは縮小させた場合、そのOTSpriteのsizeプロパティは変化するため、そのフレームのオリジナルサイズとしては利用できません。

そこで、OTSprinteのCurrentFrame()を利用して、まず現フレームのオブジェクトを取得します。すると、そのオブジェクトのimageSizeプロパティのxとyを参照することで、オリジナルサイズを知ることができます。

例えば、スプライトを1秒で10倍に拡大後、1秒で元に戻すアニメーションは、

//sprite = OTSprite
void Kakudai ()
{
    OTTween _tween;
    _tween = new OTTween (sprite, 1.0f, OTEasing.Linear);
    _tween.Tween ("size", new Vector2(sprite.CurrentFrame().imageSize.x*10, sprite.CurrentFrame().imageSize.y*10));
    _tween.onTweenFinish = this.Shukusho;
}

void Shukusyo (OTTween tween)
{
    OTTween _tween;
    _tween = new OTTween (sprite, 1.0f, OTEasing.Linear);
    _tween.Tween ("size", new Vector2 (sprite.CurrentFrame().imageSize.x, sprite.CurrentFrame().imageSize.y));
}

のように書けます。

C# IComparerインターフェイス

C#において、配列やリストの並び替えなどで使うIComparerインターフェイスについて、実装時につまづいたことを挙げておきます。

例えば、次のような実装を行ったとき、

  public class CardCompare : IComparer<Card>
  {
    public int Compare (Card a, Card b)
    {
      int ret;

      if (a.Power < b.Power) {
        ret = -1; 
      } else {
        ret = 1;
      }
      return ret;
    }
  }

これは、List<Card>というリストのソート、Cardオブジェクト内のPowerによる並び替えを行うのが目的です。
仕様的にリスト内には同一のPowerのカードはないとすると、上記プログラムでret=0を戻す必要はないと思っていましたが、実は、ret=0の系が必要です。aとbにリスト内の同一オブジェクトが指定されて呼び出されることがあるからです。(稀なケースではなく、初期の並び次第では普通にありえます。)
ですので、

  public class CardCompare : IComparer<Card>
  {
    public int Compare (Card a, Card b)
    {
      int ret = 0;

      if (a.Power < b.Power) {
        ret = -1; 
      } else if(a.Power > b.Power){
        ret = 1;
      }
      return ret;
    }
  }

のように、aとbに同一オブジェクトが指定される系を考慮して、a.Powerとb.Powerが等しい場合はret=0になるようにする必要があります。
これをしておかないと、並びが意図しないものになることがあります。(「ことがある」、、、というのが厄介でした。)

念押しで言うと、
仕様的にリスト内には同一のオブジェクトがない場合でも、IComparerのCompareメソッドの引数には同一オブジェクトが指定されて呼び出されるケースの考慮が必須
ということです。

Android NDKにおけるシグナル発生時動作

Android NDKを使用している中で二点つまづいた点があったので、挙げておきます。

まず、AndroidのDalvik仮想マシンは、SIGQUITとSIGUSR1を使用するようで、これらシグナルのハンドリングを自分のプログラムで行うことはできません。
シグナルハンドラは呼び出されませんし、また、システムコールの中でEINTRを戻すような動作も行われません。ですので、使うのであれば、SIGUSR2あたりになるかと思います。(実は、SIGUSR2もDalvikのビルドスイッチ次第では使われるそうですが。)

二つ目は、usleepというシステムコールがシグナルによる割り込みが入っていも、EINTRで戻らないということです。理由は分かりませんがそのようになっています。
これには代案があります。それは、usleepの代わりにnanosleepを使用することです。nanosleepはシグナルによる割り込みに対して、EINTRで戻ってきます。

Unityでタイマー

Unityでプログラムを組んでいるなかで一つ気がつきました。
それは一般によくあるタイマー処理というものがないということです。つまり、発火する時間と発火したときに行う処理を設定するだけ、といったようなインタフェースがないようなのです。
調べてみると、ほとんどの解決策としてGameObjectのUpdateメソッドで毎回経過時間をカウントし、期待する時間になったときに処理を行うようにしている、とのことです。
これをヒントに複数のタイマを仕掛けられる汎用クラスを作成しました。スクリプトをシーン内のGameObjectにアタッチするだけで動作します。
タイマーのキャンセルなどはなく、必要最低限の処理にしています。利用者はSetメソッドで発火時の処理(onFinishDelay)と発火時間(delay)を設定するのみです。

using System.Collections;
using System.Collections.Generic;

public class MyTimer : MonoBehaviour
{
 
  public delegate void MyTimerDelegate ();
  
  public class MyTimerParam
  {
    MyTimer.MyTimerDelegate onFinishDelay;
    float delay;
    
    public MyTimer.MyTimerDelegate OnFinishDelay {
      set {
        this.onFinishDelay = value;
      }
      get {
        return this.onFinishDelay;
      }
    }
    
    public float Delay {
      set {
        this.delay = value;
      }
      get {
        return this.delay;
      }
    }
  }
  
  List<MyTimer.MyTimerParam> parameters;
  
  // Use this for initialization
  void Start ()
  {
    parameters = new List<MyTimer.MyTimerParam> ();  
  }
 
  // Update is called once per frame
  void Update ()
  {
    List<MyTimer.MyTimerParam> deleteParameters = new List<MyTimer.MyTimerParam> ();
    
    foreach (MyTimer.MyTimerParam param in parameters) {
      param.Delay -= Time.deltaTime;
      if (param.Delay <= 0) {
        param.OnFinishDelay ();
        deleteParameters.Add (param);
      }
    }

    foreach (MyTimer.MyTimerParam param in deleteParameters) {
      parameters.Remove (param);
    }
  }

  public MyTimer.MyTimerParam Set (MyTimer.MyTimerDelegate onFinishDelay, float delay)
  {
    MyTimer.MyTimerParam param = new MyTimer.MyTimerParam ();
    param.OnFinishDelay = onFinishDelay;
    param.Delay = delay;
    
    this.parameters.Add (param);
    
    return param;
  }

}

Unityで2Dゲーム開発(7)〜Orthelloユーザ入力イベント〜

Orthelloにはオブジェクトと関係するユーザ入力に対してコールバックを呼ぶ仕組みが用意されています。
例えば、任意のスプライトを指でタッチあるいはマウスでクリックした場合に処理を実施するのに使用します。
OTObjectにonInputというdelegate指定用のフィールドがあるので、ここにdelegateを設定します。

詳しいリファレンスは

にありますが、読みながら実践してみたところ、つまづいたところがありましたので挙げておきます。

一点目は対象オブジェクト(OTObjectを継承しているもの)の「Register Input」を有効にすることです。スクリプトからプロパティを指定して有効にするか、あるいはUnityエディタ上のInspectorタブ内で「Register Input」にチェックを入れます。
これについてはリファレンスを読めばしっかり書いてあります。

次に対象のオブジェクトにはColliderコンポーネントを付ける必要がある点です。(こちらはリファレンスに書いていないように思うのですが。。。)私はこれに気づくのにサンプルソース(Orthelloパッケージ内にあるDrag Testというサンプルが参考になりました。)などを巡って小一時間かかりました。ちなみに私が付けたのは「Box Collider」です。

これら二点について実施すれば、あとはリファレンスにあるコードを参考に、ユーザ入力をハンドリングすることができます。

MonoDevelopコード生成ウィンドウからコード生成

UnityのC#スクリプトを書くために、Unityに付属していたMonoDevelopを使用しています。

継承元のメソッドをオーバライドする際に、雛形を自動生成する方法を探していました。(当然あるだろうと思っていましたので。)
メソッドを追加したい場所で、右クリックすると表示されるメニューの中に「コード生成ウィンドウを表示」というものがあり、これがどうやら自動生成をするための物らしく、必要なメソッドの一覧、生成するしないのチェックボックスらしきものが表示されました。

しかしながら、ここから実際にコードを生成するアクションが分からず、小一時間いろいろ調べていました。

そして、ようやく、(Macの場合、)Enterで入力、という答えにたどり着きました。
非常につまらない盲点でした。

ちなみにinterfaceの実装でメソッドを自動生成する場合はもっと簡単です。
コード内のinterfaceを指定している記述部分で右クリックします。メニューが表示されますので、「リファクタリング」>「暗黙に実装」で、

throw new System.NotImplementedException ();

のみを行う必要なメソッドが自動生成されます。

Unityで2Dゲーム開発(6)〜スプライト移動とアニメーション〜

表示できるようになったスプライトを任意の位置に表示したり、アニメーション(カードの表裏を切り替える)を任意に発動するには、しシーン内オブジェクトに対して、スクリプトを割り当てます。

まずは、私の場合、神様的なオブジェクトを作ります。シーン内の全ての親のようなオブジェクトです。
[GameObject]->[Create Empty]で空オブジェクトを追加し、名前を“Card”“God”に変更します。

そして、Assets配下に例えば「Scripts」というフォルダを作成し、次のような二つのスクリプトを置きます。

God.cs

using UnityEngine;
using System.Collections;

public class God : MonoBehaviour {
  public static bool isLeft;
  public static bool isRight;
  public static bool isUp;
  public static bool isDown;
  public static bool isReverse;

  public void Start()
  {
  }

  public void Update() 
  {
    //カーソル左、右、上、下、スペースが押されることで下記フラグがtrueになる
    isLeft = false;
    isRight = false;
    isUp = false;
    isDown = false;
    isReverse = false;

    if(Input.GetKey(KeyCode.LeftArrow)){
      isLeft = true;
    }

    if(Input.GetKey(KeyCode.RightArrow)){
      isRight = true;
    }

    if(Input.GetKey(KeyCode.UpArrow)){
      isUp = true;
    }

    if(Input.GetKey(KeyCode.DownArrow)){
      isDown = true;
    }
    
    if(Input.GetKeyUp(KeyCode.Space)){
      isReverse = true;
    }
  }
}

Card.cs

using UnityEngine;
using System.Collections;

public class Card : MonoBehaviour {

  private OTAnimatingSprite reverseSprite;

  private float moveSpeed = 100;
  private int moveDirX;
  private int moveDirY;
  private Vector3 movement;
  private bool isReversed;
  
  void Awake() 
  {
  }
  
  void Start()
  {
    reverseSprite = GetComponent<OTAnimatingSprite>();
    isReversed = true;
  }
  
  public void Update ()
  {    
    moveDirX = 0;
    moveDirY = 0;

    //キー押下状態によって各種制御する

    if(God.isLeft){
      moveDirX = -1;
    }
    
    if(God.isRight){
      moveDirX = 1;
    }
    
    if(God.isUp){
      moveDirY = 1;
    }
    
    if(God.isDown){
      moveDirY = -1;
    }
    
    if(God.isReverse){
      reverse();
    }

    UpdateMovement();
  }

  //移動
  void UpdateMovement() 
  {
    movement = new Vector3(moveDirX, moveDirY,0f);
    movement *= Time.deltaTime*moveSpeed;
    transform.Translate(movement.x,movement.y, 0f);
    reverseSprite.transform.position = transform.position;
  }

  //裏返し
  void reverse()
  {
    int frame;

    if(isReversed){
      reverseSprite.Play("club01");
    }else{
      reverseSprite.Play("reversed");
    }

    isReversed = (!isReversed);
  }
}

「Project」内のそれぞれのスクリプトを「Hierarchy」タブの対応するオブジェクト(Card.cs->Cardオブジェクト, God.cs->Godオブジェクト)へドラッグアンドドロップします。
これでゲーム開始させると、上下左右キーでカードが移動し、スペースキーでカードが裏返ります。

Unityで2Dゲーム開発(5)〜スプライト表示〜

今回、例としてスプライトアトラスにしたのは、トランプゲームに使うカードです。カードはあるときは表、あるときは裏というように状況によってその姿を変えます。
これを実現するためにアニメーションスプライトのフレームセットを利用します。

まずAssets > Orthello > Objects > Sprites のAnimationをHierarchyタブへドラッグアンドドロップします。
するとOT配下のAnimationsにAnimationが生成されます。

(前回生成したコンテナもそうですが、生成されたオブジェクトの名前を変更することができます。この例ではコンテナ”Container (id=xxxx)”もアニメーション”Animation (id=xxxx)”も”cards”という名前に変更します。)

Animationsに作成された”cards”を選択し、inspectorタブ内の設定を以下のようにします。

これで、裏面表示”reversed”とクラブのエースの設定ができます。

次に先ほど設定したAnimationを提供するスプライトを作成します。
Assets > Orthello > Objects > Sprites のAnimatingSpriteをHierarchyタブへドラッグアンドドロップします。

今回は、”Animating Sprite(id=xxxx)”を”card”に名前変更します。

この”card”を選択し、Inspectorタブ内の「Sprite Containe」に以前作成したSprite Atlas “cards”、また、「Animaition」にAnimation “cards”を設定します。また、ゲーム開始時にアニメーションがスタートしてしまわないように、そのした方にある「Play On Start」のチェックを外します。
また、「Physics」を”Custom”に変更しておきます。(ここを初期値の”Trigger”にしておくとアニメーションが開始するたびに位置がリセットされてしまいます。)



ここまででスプライトの設定が完了です。
では、スプライトを表示させてみましょう。
Gameタブを選択し、上部の開始ボタンをクリックします。すると開始ボタンが青に変化し、
Gameビューにカードが表示されます。

スプライトの表示はこのようにして実現できます。
ゲームとして最低限動作させるには、このスプライトに対してスクリプトをつけ、スプライトの動作を記述必要があります。
次回はスクリプトについて説明したいと思います。