HSPで関数や局所変数を使いたい

 今となっては、HSP Ver3が主流となり、HSP Ver2.61は使われなくなりつつあると思います。本講座でも、今後はVer3のみの対応と したいと思います。

 以下のような表現も、Ver3に合わせたいと思います。

 C言語を学ばれた方の中には、「HSPでも関数や局所変数が使えたらいいのになあ」と思う方もいるかと思います。HSPにもそれと 似たようなものがあります。

 1.ユーザー定義命令

戻り値のない関数、つまり命令を作りたい時には#deffunc命令を使います。

    goto *Main
    
#deffunc test
    mes "これはテストです"
    return
    
*Main
    test

 これで、「これはテストです」と表示する、testという命令ができました。#deffuncの後ろに命令名、最後にreturnを付けます。
 C言語の場合は、必ずmainという名前の関数から実行されます。Windowsプログラミングでは、必ずWinMainという関数から実行 されます。上に何が書いてあろうともです。HSPの場合は、必ず1行目から始まります。そのため、goto文でtest命令の 定義部を飛ばしてやる必要があるのです。

「#deffunc」は実際に命令を使う位置より前に置いても、後に置いてもかまいません。

    test
    stop
    
#deffunc test
    mes "これはテストです"
    return

 stopがないとその下の部分まで実行されてしまうのは、gosub文によるサブルーチンと同じです。

 このプログラムは、gosub文による以下のサブルーチンと同じ働きです。

    gosub *test
    stop
    
*test
    mes "これはテストです"
    return

 ユーザー定義命令には、引数を指定することができます。

  #deffunc 新規命令の名前 引数の型1 引数名1, 引数の型2 引数名2,……

    goto *Main
    
#deffunc nedan str sinamono, int tanka
    mes sinamono + "は" + tanka + "円" + "です"
    return
    
*Main
    nedan "ガム", 100

 "ガム"がsinamonoに、100がtankaに渡されます。引数の型には、整数型int、文字列型str、実数型double等があります。
 gosub文だといちいち
  sinamono = "ガム"
  tanka = 100
 としてからサブルーチンを呼ばなければならないので、この方がすっきりします。

 なお、関数(命令)定義時に使用される引数を仮引数、関数(命令)を実際に使用する時に渡される引数を実引数といいます。上の 場合だとsinamono、tankaが仮引数、"ガム"、100が実引数です。

    goto *Main
 
#deffunc increment int a
    a=a+1
    mes a
    return
    
*Main
    increment 10

 これはエラーになります。HSPの場合仮引数はあくまでも値を受け取るための器であって、変数ではないので、中で値を変えることは できません。
 もちろん

    goto *Main
 
#deffunc increment int a
    mes a+1	;仮引数に足し算する
    return
    
*Main
    increment 10
 や
    goto *Main
 
#deffunc increment int a
    mes a+1
    return
    
*Main
    x=10	
    increment x+2	;実引数に計算式を指定する
 といった書き方はできます。

 なお、特殊な型として引数の型にvarを指定すると、中で値を変えられるようになりますが、参照渡しという少し難しい概念が必要 となりますので、後で必要になった時に解説します。

 2.ユーザー定義関数

 戻り値がある関数を作りたい時には#defcfunc命令を使います。

  #defcfunc 新規関数の名前 引数の型1 引数名1, 引数の型2 引数名2,……

 戻り値の型は指定しません。

    goto *Main

#defcfunc half int a
    return a/2
    
*Main
    mes half(10)

 戻り値をreturnの後ろに書きます。これは、引数の半分の値を返す関数です。関数を呼ぶ場合は引数をカッコで囲む必要が あります(引数がまったくない場合も「関数名()」として関数を呼ぶ必要があります)。なお、mes half(5)とした場合aがint型なので a/2もint型となり、答は2になります。戻り値をdouble型にしたい場合は

    goto *Main

#defcfunc half int a
    return double(a)/2
    
*Main
    mes half(5)

 とする等、ユーザー側で工夫が必要です。

 条件によって返す値を変えたい場合は、以下のようにします。

   goto *Main

#defcfunc guusuu int a
    if a\2==0 {
        return "偶数"
    }
    else {
        return "奇数"
    }
    
*Main
    mes "10は" + guusuu(10) + "です"
    mes "5は" + guusuu(5) + "です"
 3.モジュール定義命令

 HSPで局所変数を使うには#module、#globalというモジュール定義命令を使います。
 #deffunc〜return、#defcfunc〜returnを#module、#globalではさんでやることによって、その命令、関数内の変数は局所変数と なります。

;1〜10の3乗を計算
    goto *Main

#module
#defcfunc sanjyou int a
    answer=1
    for i,0,3,1
        answer=answer*a
    next
    return answer
#global

*Main
    for i,1,11,1
        mes sanjyou(i)
    next

 関数sanjyou内の変数 i と、外の変数 i は名前は同じですがまったくの別物として扱われます。

    goto *Main
 
#module
#defcfunc increment int a
    return a+1
#global

*Main
    a=10	
    mes increment(a)

 このようにすると、#defcfuncで定義されている仮引数aは、increment関数内でしか有効ではないため、関数を呼び出す側の実引数の 変数と名前が同じでも問題ありません。

 グローバル変数(関数、命令の外にある変数)を関数、命令の中から参照するには、変数名に"@"をつけます。

;円の面積を求めます
    goto *Main
 
#module
#defcfunc menseki double hankei
    return hankei*hankei*pi@
#global

*Main
    pi=3.14159	; 円周率
    mes menseki(10.0)

 今回の説明の詳細は、hspprog.htmにあります。hspprog.htmはHSPをインストールしたフォルダのdoclibフォルダにあります。

ひとくちメモ:
・関数とは
 C言語を知らない方のための補足です。
 学校で学んだ関数は、このような形をしたものでした。
  y=f (x)
 プログラミングでも同じです。xを引数、yを戻り値と呼びます。正確には、関数 f が返した戻り値をyに入れているのです。 f の代わりにsanjyouとか、mensekiといった名前をつけているわけです。 つまり関数とは、引数xを受け取って、それを元になんらかの処理をし、計算結果を戻り値として返すものです。
  y=f (x1, x2, ……)
 プログラミングの場合は、このように引数が複数の場合が多いです。
 引数がまったくない場合もあります。あるいは、戻り値がない場合もあります。引数も戻り値もまったくない場合もあります。C言語では すべて関数としています。
 mes half(10)と書くと、まずhalf(10)が実行され、その戻り値がmesへの引数となります。
 HSPでもVer3で関数の考えが導入され、いくつかの命令語が関数y=f (x)の形になりました。HSP Ver2.61まではf y,xという形をして いました。つまり戻り値もまた引数に含まれ、あくまでも命令語であるという扱いでした。
 
・局所変数とは
 その関数(命令)の中でしか有効でない変数を局所変数といいます。C言語風に言えば、関数内で宣言された際に作成(メモリ内に その変数のための領域が確保される)され、関数の終了とともに破棄される(メモリ内から消える)のです。
 HSPの場合少し仕様が違っていて、関数を呼ぶたびに作成されたり破棄されたりしません。変数は保持されています。(C言語でいえば、 staticをつけて宣言した変数です。なお、特殊な型として引数の型にlocalを指定すると、関数が呼ばれると同時に作成され、関数の 終了とともに破棄されます。)
 しかし、関数の外側からは参照できない点は同じです(厳密には参照する方法があります)。
 もっとも重要な点は、関数の外側に同じ名前の変数があっても、気にしなくていいという点です。gosub文によるサブルーチンの説明を した際に、メインルーチンで使われる変数名と同じ名前を使うなとは言いませんが、メインルーチンの変数をおかしくしてしまわない ように気をつけてくださいということを書きました。それを気にしなくていいのです。
 


[目次へ][前へ][次へ] inserted by FC2 system