Lua プログラミング入門
Nishio

3

目次
第1章
1.1
1.2
1.3

はじめに
対象読者 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Lua 言語について . . . . . . . . . . . . . . . . . . . . . . . . . . . .
開発環境を整える . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1
1
1
1

第2章
2.1
2.2
2.3
2.4

Lua 言語の基礎
画面に文字を表示する . . . . . . . . . . . . . . . . . . . . . . . . .
エスケープシークエンス . . . . . . . . . . . . . . . . . . . . . . . .
コメント . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
例題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.4.1 コメントの入ったプログラム . . . . . . . . . . . . . . . . .
2.4.2 長文を表示するプログラム . . . . . . . . . . . . . . . . . . .
2.4.3 ダブルクォーテーションを表示するプログラム . . . . . . .
演習問題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

3
3
4
5
6
6
6
7
8

変数について変数の型について . . . . . . . . . . . . . . . . . . . . . . . . . . . .
変数の作り方 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
変数命名の際の注意 . . . . . . . . . . . . . . . . . . . . . . . . . .
変数への値の代入 . . . . . . . . . . . . . . . . . . . . . . . . . . . .
変数の値を表示する . . . . . . . . . . . . . . . . . . . . . . . . . .
演算 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.6.1 四則演算 . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.6.2 その他の演算 . . . . . . . . . . . . . . . . . . . . . . . . . .
3.6.3 べき乗の計算 . . . . . . . . . . . . . . . . . . . . . . . . . .
3.7 動的な変数の型 . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.8 キーボードからの値の読み込み . . . . . . . . . . . . . . . . . . . .
3.9 例題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.9.1 メートルをフィートへ変換するプログラム . . . . . . . . . .
3.9.2 2 つの値を交換するプログラム . . . . . . . . . . . . . . . . .
3.10 演習問題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

9
9
9
10
11
11
13
13
14
15
15
16
17
17
17
18

2.5
第3章
3.1
3.2
3.3
3.4
3.5
3.6

第 4 章 制御文
4.1 if else による条件分岐 . . . . . . . . . . . . . . . . . . . . . . . . . .
4.1.1 if else の書き方 . . . . . . . . . . . . . . . . . . . . . . . . .
4.1.2 偽条件の判定 . . . . . . . . . . . . . . . . . . . . . . . . . .
4.1.3 関係演算子 . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.1.4 論理演算子 . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.2 while による繰り返し . . . . . . . . . . . . . . . . . . . . . . . . . .
4.3 for による繰り返し . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.4 repeat による繰り返し . . . . . . . . . . . . . . . . . . . . . . . . .
4.5 break を使ったループの脱出 . . . . . . . . . . . . . . . . . . . . . .
4.6 Lua に存在しない制御文 . . . . . . . . . . . . . . . . . . . . . . . .
4.7 例題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.7.1 九九表を作成するプログラム . . . . . . . . . . . . . . . . .
4.7.2 文字コード表を表示するプログラム . . . . . . . . . . . . . .
4.7.3 足し算，引き算を行うプログラム . . . . . . . . . . . . . . .
4.8 演習問題 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

19
19
19
20
21
22
23
24
26
27
28
29
29
30
30
31

第5章
5.1
5.2
5.3
5.4
5.5
5.6
5.7
5.8

関数
関数について . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
関数の作り方 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
関数の戻り値 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
何も返さない関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . .
変数に関数を代入する . . . . . . . . . . . . . . . . . . . . . . . . .
関数中に関数を定義する . . . . . . . . . . . . . . . . . . . . . . . .
無名関数 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
標準ライブラリ . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.8.1 基本ライブラリ . . . . . . . . . . . . . . . . . . . . . . . . .
5.8.2 文字列操作ライブラリ . . . . . . . . . . . . . . . . . . . . .

33
33
33
35
36
37
38
39
39
39
42

第 6 章 C 言語との連携
6.1 Lua スタック . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.1.1 スタックとは . . . . . . . . . . . . . . . . . . . . . . . . . .
6.1.2 Lua の初期化 . . . . . . . . . . . . . . . . . . . . . . . . . .
6.1.3 Lua スタックへ値をプッシュする . . . . . . . . . . . . . . .
6.1.4 Lua スタックから値をポップする . . . . . . . . . . . . . . .
6.1.5 Lua スタックの操作 . . . . . . . . . . . . . . . . . . . . . . .
6.1.6 Lua スタックのサイズ . . . . . . . . . . . . . . . . . . . . .
6.1.7 Lua スタックの値の参照 . . . . . . . . . . . . . . . . . . . .

43
43
43
45
45
48
50
56
58

4

6.2

6.3

6.1.8 Lua スタック上のテーブルの格納と参照 . . . . . . . . . . .
C から Lua を呼び出す . . . . . . . . . . . . . . . . . . . . . . . . .
6.2.1 Lua ファイルを読み込む . . . . . . . . . . . . . . . . . . . .
6.2.2 Lua のグローバル変数を取得する . . . . . . . . . . . . . . .
6.2.3 Lua 関数を呼び出す . . . . . . . . . . . . . . . . . . . . . . .
6.2.4 Lua にグローバル変数を登録する . . . . . . . . . . . . . . .
Lua から C を呼び出す . . . . . . . . . . . . . . . . . . . . . . . . .
6.3.1 C 関数を呼び出す . . . . . . . . . . . . . . . . . . . . . . . .
6.3.2 関数毎の Lua スタック . . . . . . . . . . . . . . . . . . . . .
6.3.3 テーブルに C 言語関数を登録する . . . . . . . . . . . . . . .

59
64
64
66
67
70
72
72
74
78

1

第1章
1.1

はじめに

対象読者

本書の対象読者は C 言語プログラミング（または C++, C#, JAVA）経験者です．言語の基本的な文法を知っている（if, for, while, 関数の作り方を知っている）
程度で十分です．しかしできるだけ C 言語 (または C 言語に似た言語）を知らな
い方でも理解できるように説明していくつもりです．

1.2

Lua 言語について

本書の対象読者を C（または C に似た）言語としたのには理由があります．それはたぶん Lua 言語のみを使ってプログラムを作ることが殆ど無いと思われるか
らです．Lua 言語は C 言語から呼び出されて，または組み込まれて使われる言語です．
以下は今度書く

1.3

開発環境を整える

3

第2章

Lua 言語の基礎

この章では画面に Hello World と表示するプログラムを作成していきたいと思います．同時にここで Lua 言語の基礎を学んでいきます．

2.1

画面に文字を表示する

次のソースコード1 をエディタに貼り付けてください．

print ("Hello World!")1

プログラムは 1 行だけです．C 言語とは違い main 関数はありません．このプログラムの実行結果は以下のようになります．
¶
実行結果

Hello World!

µ³´

画面に文字を表示する時は print 関数を使用します．
¶
書式³

print (” なにか表示したい文章をここに書く ”)µ´

print 関数は以下のように書くこともできます．
print ("Hello World!")
print (’Hello World!’)
print "Hello World!"
print ([[Hello World!]])上から 3 つまでのコードはすべて同じ意味です．文字列をダブルクォーテーショ
ンで囲んでもシングルクォーテーションで囲んでもどちらでもよいです．ただし 4番目だけは少し意味が違います．これは次節のエスケープシークエンスで説明します．

1

ソースコードとはプログラミング言語で書かれた文章の事です．

2.2 エスケープシークエンス¶
C 言語との違い³• プログラムはメイン関数から実行されるわけではなく，上から下に実行される• printf ではなく print• コードの終端にセミコロン (;) が無い
µ

2.2

´

エスケープシークエンス

たとえば，print 文の中の文字列で，改行をしたい場合があるかもしれません．
改行を行う場合，特殊な文字を使って改行を行います．改行の場合は\n という文
字を使います．\と n 2 つの文字を組み合わせて改行という意味です．2

print("Hello\nWorld!")
このようにして使います．
¶
実行結果

³

Hello
World!

µ´

改行文字のほかに，表 2.1 がエスケープシークエンスとしてあります．
表 2.1: エスケープシークエンス一覧
記号

意味

\n
\a
\t
\b
\’
\"
\\

改行
BEEP 音（警告音）
タブ
バックスペース
シングルクォーテーション
ダブルクォーテーション
バックスラッシュ（日本語の端末の場合, 円マーク）

さて，先ほど出てきた print ([[Hello World!]]) という print 関数の書き方ですが，
これはエスケープ文字を無視して文字列をそのまま出力します．例えば次のようなコードがあったとします．
2

日本語の場合バックスラッシュは円マーク￥を使います.

4

第 2 章 Lua 言語の基礎

print([[Hello\nWorld!]])
このコードの実行結果は以下のようになります．
¶
実行結果

³

Hello\nWorld!
µ´

文字列をそのまま出力するので，改行などもそのまま表示されます．例えば次のような場合です．
1
2
3
4

print([[Hello
World!
こんにちは世界]])
このプログラムの実行結果は以下のようになります．
¶
実行結果

³

Hello
World!
こんにちは世界
µ

2.3

´

コメント

C 言語同様プログラム内にコメントを書くことができます．
コメントとは，ソースコード（自分がＣ言語で書いた文章の事）の中で，そのソースが何を意味しているかを書いておきたいときに使います．たとえば次のよ
うなソースがあったとします．
1

print ("Hello World!") --Hello World!と画面に表示する「--Hello World!と画面に表示する」という部分がコメントです．マイナスを二つ重ねています．
「--」以降の行末までコメントとなります．
ここで，複数行コメントを書きたい場合があると思います．

--この
--部分が
--コメントと--なります5

2.4 例題
これでもよいですが，Lua では複数行のコメントを書く場合は，--[[と]] で囲
むことでコメントとすることができます．

--[[
この
部分が
コメントと
なります
]]

2.4

例題

2.4.1

コメントの入ったプログラム

このプログラムで注意したい点は「This line is not displayed.」という部分が実
行結果には表示されていないことです. コメントアウトされている部分はたとえ命令であっても無視されます. また，C 言語の printf とは違い，print 関数を一度実行すると，文章の終わりに自動的に改行が付け加えられます．
1
2
3--print 関数の終わりは勝手に改行される
print("This is a test program ")print("without indented. ")

4
5
6
7
8

--[[
この部分はコメントアウトされているので表示されない
print("This line is not displayed. ")
]]
¶
実行結果

³

This is a test program
without indented.

µ

2.4.2

´

長文を表示するプログラム

一行で表示する文字数が多い場合それを同じライン上で書くとコードが読みにくくなる場合があります．この場合の修正方法を学んでいきましょう．
print 関数を一回だけ使い, There are 10 types of people in this world. Those
who understand binary and those who don’t. Which one are you? という文章を6

第 2 章 Lua 言語の基礎表示するとしましょう．しかし同じライン上で書くとコードが読みにくくなってしまいます．この場合以下のようにコードを書くこともできます．
1
2
3
4--この用にコードを書くこともできる
print("There are 10 types of people in this world." ..
"Those who understand binary and those who don’t." ..
"Which one are you?" ).. という部分に注目してください．これは複数の文字列をつなぎ合わせるときに使用します．詳細は次章で説明します．
¶³
実行結果
There are 10 types of people in this world.Those who understand binary andthose who don’t.Which one are you?
µ

´

2.4.3

ダブルクォーテーションを表示するプログラム

次のような文字列を表示するプログラムを作りたいとします．

He said, ”How dare you do to me like that!”
この場合次のようなコードを作成してみましたがうまくいきませんでした．

print("He said, "How dare you do to me like that!"")--error

このコードはエラーが出て実行することができません．ではどのようにすれば”(ダブルクォーテーション）を表示されるのでしょうか？
その答えは先ほども登場したエスケープシークエンスを使うことで解決できます．

print("He said, \"How dare you do to me like that!\"")
または次のように書いてもよいでしょう．

print([[He said, "How dare you do to me like that!"]])
このようにできることも覚えておきましょう．
¶
実行結果

³

He said, ”How dare you do to me like that!”µ´7

2.5 演習問題

2.5

演習問題

問題 1
自分の名前を画面上に表示するプログラムを作成せよ．
問題 2
ビープ音を鳴らすプログラムを作成せよ．
問題 3

print 関数を一度だけ使い次の文章を表示するプログラムを作成せよ．ただしソースコードが読みやすくなるように工夫すること.
The ICMP source quench message is the TCP/IP equivalent of telling anothercomputer: ”I can’t keep up with all the traffic you’re sending me - slow down,please.” 33Firewalls FOR DUMMIES by Brain Komar, Ronald Beekelaar, and Joern Wettern, PhD よ
り引用

8

9

第3章

変数について何か計算をしたとき，その計算結果を覚えておきたいときがあると思います．その時使うものが変数です．変数とは，値を保存することができる箱です．

3.1

変数の型について

Lua には C 言語のような変数の型は一応存在してはいますが，変数の型を意識しなくてもよいような設計となっています．例えば hoge という名前の変数を宣言したら，その変数にはどんな値でも代入できます．例えば整数も代入できますし，
少数や文字列なども代入できます．ここで代入とは変数つまり箱の中に値を入れることです (この表現は正確ではないですが，いまの段階ではそう思っていただい
てかまいません）．
¶³
C 言語との違い• 変数の型を意識しなくてもよい
µ

3.2

´

変数の作り方では，実際変数を作ってみましょう．変数を作りたい場合，次のようにします．

hoge = 10
これは，hoge という名前の変数を作れという意味です．箱には名前をつけることができます．そしてこの hoge には 10 という値が入っています．C 言語とは違って初期化していない変数は作ることができません．例えば次のようなコードはエラーとなります．

hoge --error
変数を複数宣言する場合は次のように記述することもできます．

foo = 10 bar = 20

3.3 変数命名の際の注意
上記の宣言は

foo = 10bar = 20と全く同じ意味になります．また,

foo, bar = 10, 20
も同じ意味となります．
C 言語とは違い，変数はどこでも宣言できます．また，複数の値を 1 行で書き換える多重代入が可能です．
また，これも重要ですが，Lua の変数は特に指定が無い限りグローバル変数となります．グローバル変数の意味は変数のスコープの所で説明します．
¶
C 言語との違い³• 変数はいかなるところでも定義できる• 変数は指定が無い限りグローバル変数となる
µ

3.3

´

変数命名の際の注意

変数名を付ける際に，次のようなルールがあります．

• 先頭は英字か_(アンダースコア）でなければならない
数字ではダメです．

• 同じ名前の変数が２つ存在する事は基本的にはできない
ただし変数のスコープが違えば同じ名前の変数を複数つくれます．スコープの説明は今はしません．

• 予約語は使えない
予約語 (表 3.3）とは，if や while など，Lua 言語の文法の一部の事です．

10

第 3 章 変数について

表 3.1: 予約語一覧

and
end
in
repeat

3.4

break
do
false
for
local
nil
return thenelsefunctionnottrueelseif
if
or
until

while

変数への値の代入

変数に何か値を入れてみましょう．例えば，10 という値を箱に入れたい場合は次のようにします．

hoge = 10
この = という記号は，式の右側の値を左側に代入せよ，という意味です．数学のイコールという意味ではないので注意してください．
では，数学でよくある x = 10（x は 10 である）といった本当にイコールの意味を使いたい場合はどうすればよいでしょうか．これは，if 文という所でしっかり説明しますが，今軽く説明しておくと，== という記号を使います．イコールを二つ繋げて書くと，本当に数学でいうイコールという意味になります．
Lua では多重代入も可能となっています．

hoge, piyo = 10, 5
hoge に 10 を代入し，piyo には 5 を代入しています．

3.5

変数の値を表示する

変数を画面上に出力したい場合，どのようにしたらよいでしょうか．例として，
int 型の hoge という箱に 10 という値を代入して，その箱の中身を画面上に表示させてみます．

hoge = 10
print(hoge)
このプログラムを実行すると，次のように画面上に表示されると思います．
¶
実行結果

³

10

µ

´

複数の値を表示させることもできます．

11

3.5 変数の値を表示する
hoge = 10
piyo = 20
print(hoge, piyo)
このようにカンマ区切りで複数の値が表示できます．
¶
実行結果

³

10 20

µ

´

また文字と数値なども一緒に表示させることができます．文字列と数値，または文字列と文字列を結合して表示させる場合，連結演算子 .. を使います．
1
2

hoge = 10
print("hoge の値は" .. hoge .. "です")
¶
実行結果

³

hoge の値は 10 ですµ´

Lua には C 言語の printf 関数と似たものが存在します．それが string.format() 関
数です．この関数は文字列の書式を指定して画面に表示します．書式指定子一覧
は表 3.2 の通りです．
表 3.2: 書式指定子
記号

意味

%d
%u
%o
%x
%f
%c
%%

整数の 10 進法として出力
符号なし整数の 10 進法として出力整数の 8 進法として出力整数の 16 進法として出力
小数点表示
1 文字出力％を出力

string.format() 関数を使って数値を表示させてみましょう．
1
2
3
4

hoge = 10
print( string.format( "hoge の 10 進数の値は%d です" ,hoge) )print( "hoge の 16 進数の値は" ..
string.format("%x",hoge) .. "です")12

第 3 章 変数について
¶
実行結果

³

hoge の 10 進数の値は 10 ですhoge の 16 進数の値は a ですµ´

他にもいろいろ試して見ましょう．
1
2
3

hoge = 10
piyo = 20
foo = 30.256

4
5
6
7
8
9
10
11

print( string.format("hoge の値は%d です",hoge) )print( string.format("piyo の値は%d です",piyo) )print( string.format("値は%d です", 50) )print( string.format("hoge は%d piyo は%d です",hoge,piyo) )print( string.format("foo の値は%f です",foo) )print( string.format("hoge の値は%f です",hoge) )print( string.format("foo の値は%d です",foo) )
¶
実行結果

³

hoge の値は 10 ですpiyo の値は 20 です
値は 50 です
hoge は 10 piyo は 20 です
foo の値は 30.256000 ですhoge の値は 10.000000 です
foo の値は 30 です
µ

´

3.6

演算

3.6.1

四則演算

数学でもお馴染みの四則演算，つまり「足し算」「引き算」「掛け算」「割り算」
を Lua 言語でも行うことができます．その方法は簡単です (表 3.7）．

13

3.6 演算

表 3.3: 四則演算
記号

意味

+
−
∗
/

足し算
引き算
掛け算
割り算

簡単な計算の例
12345x = 10y = 20
print("x+y は" .. x + y .. "です")y = y - x
print("y の値は" .. y .. "です")
このプログラムの実行結果は次のようになります．
¶
実行結果

³

x+y は 30 です
y の値は 10 です
µ

´

3.6.2

その他の演算値の符号の反転をしたい場合は次のようにします．

x = 10
print("反転した値は" .. -x .. "です")
¶
実行結果

³

反転した値は-10 ですµ´

剰余，つまり割り算の余りを求めたい場合は，次のようにします．

x = 10 y = 3
print("余りは" .. x % y .. "です")
¶
実行結果

³

余りは 1 ですµ´

14

第 3 章 変数について

表 3.4: 変数の型
型
nil
booleannumberstringfunction
userdata
thread
table

3.6.3

意味
nil
論理型
数値
文字列
関数
ユーザ定義型
スレッド
テーブル

べき乗の計算べき乗とは，例えば x の 2 乗，つまり x*x などのことをいいます．Lua でべき乗の計算をしたい場合， 2^3 と ^ を使って表現します． 2^3 は 2 の 3 乗という意
味です．

print( "2 の 3 乗は " .. 2 ^ 3 .. "です")
¶
実行結果

³

2 の 3 乗は 8 です
µ

3.7

´

動的な変数の型

Lua は変数の型を意識しなくてもよいと説明しました．しかし一応変数の型は存在しています．それは表 3.7 に示した 8 つの基本型です．
nil とは何もない値という意味です．C 言語や JAVA でいう null と同じ意味です．
boolean は論理型，つまり true と false の二つの値を持つものです．number は数値を入れることができるものです．string が文字列を表しています．その他の型については現時点では説明しません．
Lua の場合は変数が型を持っているわけではなく，値が型を持っています．つまり，変数に入れる値によって型が動的に変化していくわけです. ここで現在変数が何型であるかを調べるため type() 関数を使用して，型を調べてみましょう．
1

hoge = nil
15

3.8 キーボードからの値の読み込み
2
3
4
5
6
7
8

print("hoge の現在の型は" .. type(hoge) .. "です")hoge = "Hello"
print("hoge の現在の型は" .. type(hoge) .. "です")hoge = 33
print("hoge の現在の型は" .. type(hoge) .. "です")hoge = true
print("hoge の現在の型は" .. type(hoge) .. "です")
¶
実行結果

³

hoge の現在の型は nil です
hoge の現在の型は string です
hoge の現在の型は number ですhoge の現在の型は boolean ですµ´

このように入れる値によって型が動的に変化します．

3.8

キーボードからの値の読み込み

キーボードから何か値を入力して，変数の中に代入したい場合があると思います．そういった場合に使うのが io.read() 関数です．
12
34hoge = nil
print("何か文字列を入力してください :")hoge = io.read()print("入力された文字は" .. hoge .. "です")
¶
実行結果

³

何か文字列を入力してください :hello world
入力された文字は hello world です
µ
¶
実行結果

´
³

何か文字列を入力してください :55
入力された文字は 55 です
µ

´

16

第 3 章 変数について

3.9

例題

3.9.1

メートルをフィートへ変換するプログラム

¶
仕様

³

メートルからフィートへ変換するプログラムを作成せよ. メートルに 3.2 をかけることによってフィートを求めることができる.
µ

1
2
3
4

´

io.write("メートルの値を入力してください :")meter = io.read()answer = meter * 3.2
print( meter .. "メートルは" .. answer .. "フィートです")

io.write() 関数は print 関数と使い方は同じです．ただし io.write() 関数は文章の最後に改行が自動付加されません．
¶³
実行結果
メートルの値を入力してください :27
27 メートルは 86.4 フィートです
µ

3.9.2

´

2 つの値を交換するプログラム

¶
仕様

³

変数 hoge には 10 が，piyo には 5 が代入されている．この二つの値を交換せよ．
µ

1
2
3
4
5
6

´

hoge, piyo = 10, 5
print("hoge の値は" .. hoge .. " piyo の値は" .. piyo .. "です")tmp = hoge
hoge = piyo
piyo = tmp
print("hoge の値は" .. hoge .. " piyo の値は" .. piyo .. "です")

解答は一通りではありません．多重代入を使う事で tmp 変数を使わなくて済み
ます．
1
2
3
4

hoge, piyo = 10, 5
print("hoge の値は" .. hoge .. " piyo の値は" .. piyo .. "です")
hoge, piyo = piyo, hoge
print("hoge の値は" .. hoge .. " piyo の値は" .. piyo .. "です")173.10 演習問題
¶
実行結果

³

hoge の値は 10 piyo の値は 5 ですhoge の値は 5 piyo の値は 10 です
µ

3.10

´

演習問題

問題 1
分を時間に変換するプログラムを作成しなさい．例えば，ユーザが 180 と入力
したら 3 と表示する表示するプログラムである．
問題 2
セ氏温度を華氏温度に変換するプログラムを作成せよ．セ氏温度 (F) と華氏温度 (C) には次のような関係がある．

9F = C + 32
5

18

(3.1)

19

第4章
4.1

制御文

if else による条件分岐

if else 構文 (英語で if はもし〜だったら，else はそうでなかったら，という意味)
は, 条件分岐をする際に使用する構文です．

4.1.1

if else の書き方¶
書式

if ( 条件式 ) then
条件式が真であるときの処理
else
条件式が偽であるときの処理
end

µ

³

´

条件式にはカッコが無くても構いません．
では, 実際に if else 構文を使ってみましょう．
ここでテストの成績を判定するプログラムを作ってみましょう．もし点数が 60点以上であったら合格を，そうでなかったら不合格を表示するプログラムを作り
ます．
1
2
3
4
5
6

result = 70
if result >= 60 thenprint("合格")else
print("不合格")
end
¶
実行結果

³

合格
µ

result が 60 以上であるかを比較する際には，関係演算子>=を使用します．

´

4.1 if else による条件分岐
result の値を 50 にしてみると次のようになります．
¶
実行結果

³

不合格
µ

´

else は書かなくてもかまいません．
1
2
3
4

hoge = 10
if ( hoge == 10 ) thenprint("Hello world")
end

このプログラムは hoge が 10 と等しい時にだけ Hello world を出力します．
ここで注意して欲しいのは, hoge が 10 と等しいと判定する場合，hoge = 10 ではなく,hoge == 10 であるということです.
また, 条件を複数書きたい場合, 次のように書きます．
1

hoge = 8

2
3
4
5
6
7
8
9
10
11

if( hoge == 10 ) then--A の処理
elseif( hoge == 9) then--B の処理
elseif( hoge == 8 ) then--C の処理else--D の処理end

第 2，第 3 の判定を付けたい場合，elseif を使用します．この場合 C の処理が実行されることになります. ここでもし hoge が 9 であるならばＢの処理が行われま
すし,6 ならば D の処理が実行されることになります.

4.1.2

偽条件の判定

さて，次のようなコードを書いたらどのような実行結果となるでしょうか．
1
2
3

hoge = 1
if ( hoge ) thenprint("first")
20

第 4 章 制御文
4

end

5
6
7
8
9

hoge = 0
if ( hoge ) thenprint("second")
end

10

hoge = false
if ( hoge ) thenprint("third")
end

11
12
13
14
15

hoge = nilif ( hoge ) thenprint("fourth")
end

16
17
18
19

¶
実行結果

³

first
secondµ´

さて, カッコの中には何か式を書かなくてはなりませんが, この場合は変数名のhoge としか書いてありません. これはどういう意味でしょうか.
実はこういった場合, カッコの中の値が false,nil であるか false,nil 以外であるかで判定します. false,nil でない場合は処理を行い，そうでない場合は処理を行いません．
¶
C 言語との違い³• 0 は偽条件ではない
µ

4.1.3

´

関係演算子

2 つの変数を比較して, 式が正しいか誤りかを求める時に使う演算子を関係演算子といいます. 例えば 4.1 のようなものが存在しています.

例えば次のようなコードを書いたとします．

21

4.1 if else による条件分岐

x < y
x > y
x <= yx >= yx == yx ~= y1
2
3
4
5
6

表 4.1: 関係演算子
x が y より小さかったら真, そうでなかったら偽x が y より大きかったら真, そうでなかったら偽x が y 以下であれば真, そうでなかったら偽x が y 以上であれば真, そうでなかったら偽x が y と等しければ真, そうでなかったら偽x が y と等しくなければ真, そうでなかったら偽hoge = 1
if( hoge ~= 1 ) thenprint("Hello")
else
print("World")end
この場合，hoge は 1 なので，条件が偽となり，World が表示されます．
¶
C 言語との違い³• != ではなく ~=
µ

4.1.4

´

論理演算子

次のようなコードを書いたとします.
1

hoge, piyo = 10, 20

2
3
4
5
6
7

if( hoge == 10 ) thenif( piyo == 20 ) thenprint("hello")end
end

この式は hoge が 10 であり, かつ piyo が 20 である時,Hello が表示されます．ここで論理演算子というものが存在します (表 4.2）.

つまり, 先ほどの例をこの論理演算子を使って書き直すと次のようになります.

22

第 4 章 制御文

表 4.2: 論理演算子

x == 10 and y == 20
x == 10 or y == 20
not x

1

x が 10 かつ y が 20
x が 10 または y が 20
x の否定

hoge, piyo = 10, 20

2
3
4
5

if( hoge == 10 and piyo == 20) thenprint("Hello")
end
ここで,x の否定とはどういうことを意味しているでしょうか.

1
2
3
4
5
6

hoge = 10
if( not hoge ) thenprint("Hello")
else
print("World")
end

not hoge は hoge が 10 でない場合は条件が真となり，そうでない場合は条件が偽となります．よってこのプログラムは条件が偽となり，World と表示されます．
¶³
C 言語との違い• &&, ｜｜, ! ではなく and, or, not
µ

4.2

´

while による繰り返し

¶
書式

³

while ( 条件式 ) do
処理
end

µ

´

条件式にはカッコが無くてもかまいません．
繰り返し処理を行いたい場合は while 構文を使います．条件式が真の場合，処理が繰り返し行われます．たとえば Hello world と 10 回表示するプログラムを while
を使って作ってみます.

23

4.3 for による繰り返し
1
2
3
4
5

i = 1
while i <= 10 doprint ( i .. "回目:Hello world!" )i = i + 1
end
¶
実行結果

³

1 回目:Hello world!
2 回目:Hello world!
3 回目:Hello world!
4 回目:Hello world!
5 回目:Hello world!
6 回目:Hello world!
7 回目:Hello world!
8 回目:Hello world!
9 回目:Hello world!
10 回目:Hello world!
µ´

条件式は if と同じです. if と同じということは次のようなコードを書いた場合どうなるでしょうか．
1
2
3

while true doprint ( "Hello world!" )end
これは, 条件は常に真ということになります．つまり無限ループに陥ります.

4.3

for による繰り返し

for 構文には Numeric for と Generic for の 2 種類が存在します．Generic for は難しいので，また後の章で説明することとします．ここでは Numeric for について説明していきます．
Numeric for も while 同様繰り返しの処理を行う場合に使用します．ただし，whileとは違い，終了条件が数値でしか指定できません．
¶³
書式
for 初期値, 終了値, 増加量 do
処理
end

µ

´

24

第 4 章 制御文
増加量は省略することができます．その場合，自動的に増加量は 1 となります．
前節で登場した Hello world を 10 回表示するプログラムを for を使って書き直すと次のようになります．
1
2
3

for i = 1, 10, 1 do
print( i .. "回目:Hello world!")end

i が 1 で始まり，i が 10 になるまで，i を 1 ずつ増加させていきます．つまり，iが 10 以下の場合に繰り返しが行われます．
¶³
実行結果
1 回目:Hello world!
2 回目:Hello world!
3 回目:Hello world!
4 回目:Hello world!
5 回目:Hello world!
6 回目:Hello world!
7 回目:Hello world!
8 回目:Hello world!
9 回目:Hello world!
10 回目:Hello world!
µ´

増加量は省略することができます．その場合は，自動的に 1 が割り当てられます．
1
2
3

for i = 1, 10 doprint( i .. "回目:Hello world!")
end
実行結果は先ほどと同じです．
増加量を 4 に変更してみましょう．どのような実行結果となるでしょうか．

1
2
3

for i = 1, 10, 4 doprint( i .. "回目:Hello world!")
end
¶
実行結果

³

1 回目:Hello world!
5 回目:Hello world!
9 回目:Hello world!
µ

´

25

4.4 repeat による繰り返し
for を使う上で注意しなければならないことがあります．それは，初期値で定義した変数（ループ変数）は for 文の中でのみ有効だということです．つまり，for を抜けた時点でループ変数は消滅してしまいます．
例えば次のようなコードを書いたとします．
1
2
3
4
5
6

for i = 1, 10, 4 doprint( i .. "回目:Hello world!")end
if i == nil thenprint ("i は定義されていません")
endfor 文で使用している i と if 文で使用している i は別物です．実行結果は以下のようになります．
¶³
実行結果
1 回目:Hello world!
5 回目:Hello world!
9 回目:Hello world!
i は定義されていませんµ´

i は定義されていないので，nil となっています．

4.4

repeat による繰り返し

repeat を使ってループを行うこともできます．repeat は while と違い，repeat 内の処理は最低 1 回は必ず行われます．処理を行ったあと，条件式を判定し，条件が真の場合，ループが終了します．
¶³
書式
repeat処理
until (条件式)µ´

条件式が偽の場合，処理が繰り返し行われます．真の場合ではないので注意してください．
12
3

i = 1
repeatprint (i .. "回目:Hello world!")26

第 4 章 制御文
45i = i + 1
until ( i >= 5 )
¶
実行結果

³

1 回目:Hello world!
2 回目:Hello world!
3 回目:Hello world!
4 回目:Hello world!
µ

4.5

´

break を使ったループの脱出

繰り返し処理を実行している間に break 文を使うと，いつでもループから脱出することができます．例えば次のようなプログラムを書いたとします．
1
2
3
4
5
6
7

for i = 0, 10 doprint( "i の値:" .. i )if ( i == 5 ) then
break
end
end
print("脱出")
¶
実行結果

³

i の値:0i の値:1i の値:2i の値:3i の値:4i の値:5脱出µ´

break は必ずブロックの最後でしか使うことができません．ブロックの最後とは，
具体的に以下のような場所です．
• end の手前
• repeat - until の until の手前 等

27

4.6 Lua に存在しない制御文
上記の場所以外では break は定義できません．しかしデバッグ中に，例えば処理の途中で break したい場合があるかもしれません．次のようなコードがあった
とします．
1
2
3
4
5
6

for i = 0, 10 doprint("なにか処理")--本当はここで break したい
print("別の処理")
end
print("脱出")

まあ，このようなコードを書くことは普段ないとは思いますが．
とにかく，途中で break したい場合は，ブロックを for の途中に作ればよいのです．ブロックを作るには，do - end を使用します．
¶
書式

³

do
処理

end

µ

´

よって，次のように書き直せば，処理の途中で break が行えます．
1
2
3
4
5
6
7
8

for i = 0, 10 doprint("なにか処理")dobreak;
end
print("別の処理")
end
print("脱出")
¶
実行結果

³

なにか処理
脱出
µ

4.6

´

Lua に存在しない制御文

多くのプログラミング言語には存在していても，Lua には存在していない制御
文があります．

28

第 4 章 制御文
例えば switch 構文は Lua にはありません．switch はテーブルを使うことで表現できますが，ここではその方法は割愛します．
また，繰り返し処理中で使用する continue 文も存在しません．

4.7

例題

4.7.1

九九表を作成するプログラム

¶
仕様

³

九九を表示するプログラムを作成せよ．九九表は以下のように表示させる．

1
2
3
4
5
6
7
8
9

2
4
6
8
10
12
14
16
18

3
6
9
12
15
18
21
24
27

4
8
12
16
20
24
28
32
36

5
10
15
20
25
30
35
40
45

6
12
18
24
30
36
42
48
54

7
14
21
28
35
42
49
56
63

8
16
24
32
40
48
56
64
72

9
18
27
36
45
54
63
72
81

µ

1
2
3
4
5
6

´

for i = 1, 9 dofor j = 1, 9 do
io.write( string.format("%3d", i*j) )end
io.write("\n")end

io.write 関数は print 関数と同じ機能を果たします．ただし，文章の最後に改行が自動付加されません．
string.format の中に%3d というものを使いましたが，これは 3 文字分のスペースを確保して表示するという意味です. このようにすると綺麗に表示することができます．5 文字分のスペースを確保したい場合は,%5d とすればよいです．

29

4.7 例題

4.7.2

文字コード表を表示するプログラム

¶
仕様

³

0〜255 までの文字コードを表示するプログラムを作成せよ．10 進法の値，16進法の値，文字を表示することとする．
0 0
1 1
（略)

65 41 A66 42 B
（略）
µ

1
2
3

´

for hoge = 0, 255 do
print( string.format("%3d %3x %3c", hoge, hoge, hoge) )
end

4.7.3

足し算，引き算を行うプログラム

¶
仕様

³

利用者の選択により足し算, 引き算ができるプログラムを作成せよ．
µ

1
2
3
4

´

print("1 : 足し算を行う")
print("2 : 引き算を行う")
io.write("番号を入力してください :")select = io.read()

5
6
7
8
9

io.write("1 番目の数 :")
hoge = io.read()
io.write("2 番目の数 :")piyo = io.read()1011

if( select == "1" ) then30

第 4 章 制御文

print( hoge .. " + " .. piyo .. " = " .. hoge + piyo )elseif( select == "2" ) thenprint( hoge .. " - " .. piyo .. " = " .. hoge - piyo )
end

12
13
14
15

注意点が一つあります．それは，io.read 関数で読み取ることができるのは文字です．よって，select は String 型となっています．なので，if( select == 1 ) thenとはできません．
¶
実行結果³

1 : 足し算を行う
2 : 引き算を行う
番号を入力してください :1
1 番目の数 :15
2 番目の数 :10
15 + 10 = 25
µ
¶
実行結果

´
³

1 : 足し算を行う
2 : 引き算を行う
番号を入力してください :2
1 番目の数 :15
2 番目の数 :10
15 - 10 = 5

µ

4.8

´

演習問題

問題 1
キーボードから数字を受け取り, その絶対値を表示するプログラムを作成せよ.
絶対値とは数字 0 からの距離のことである．例えば，-7 ならば 0 からの距離は 7 な
ので絶対値は 7 である．

31

33

第5章
5.1

関数

関数についてLua に限らず，多くのプログラミング言語に欠かせない概念の一つとして関数というものが存在します．実は今まで関数を何回も使っていました．例えば print
ですが，これは関数です．io.read も関数です．関数とはいくつもの命令を集め１つの塊として定義したものです．同じ処理を何回も行いたい場合は，関数を１つ定義して呼び出すだけでよいです．

5.2

関数の作り方では，関数を作ってみましょう．関数は次のように定義します．
¶
書式

function 関数名 ( 引数 )
処理
end

µ

³

´

ここで，二つの値を引数として渡し，その和を求める関数を作ってみましょう．
1
2
3function sum(x, y)
return x + y
end

4
5
6

hoge = 10
piyo = 20789result = sum( hoge, piyo )print( hoge .. " + " .. piyo .. " = " .. result )
¶
実行結果

³

10 + 20 = 30µ´

5.2 関数の作り方
まず sum 関数を使う前に，関数を定義しておかなければならない事に注意してください．関数には好きな名前をつけてください．ただし，すでに使われている
関数名や変数名は使わないでください．例えば，print などの名前をつけないでください．関数命名のルールは変数の場合と同じです．
¶
C 言語との違い³• プロトタイプ宣言は無いµ´

さて，関数を呼び出す際に sum( hoge, piyo ) としました．関数を呼び出す
際には引数と呼ばれるものを渡します．この引数とはどういったものでしょうか．
図 5.1 を使ってその説明をします．

図 5.1: 関数の引数と戻り値

図 5.1 は引数の様子を示した図です．呼び出した側の引数を実引数といい，呼び出された側の引数を仮引数といいます．このとき，実引数の値が仮引数の値にコ
ピーされます．つまり，
1234function func(x, y)x = 10y = 20
end

5
6
7
8

hoge = 12
piyo = 22
func( hoge, piyo )34

第 5 章 関数
9print(hoge, piyo )10としても，x,y は hoge, piyo のコピーなので，中身をいくら書き換えても呼び出
しもとの hoge, piyo には影響を及ぼしません.
引数に関して，もしかしたら何も受け取る必要が無い場合があるかもしれません．そういった場合は，引数の中は空にしておきます．
関数の戻り値に関しては次節で説明します．

5.3

関数の戻り値関数には戻り値と呼ばれるものが存在しています．前節のプログラムと図 5.1 を見てください．
return は値を関数を呼び出した側に返す命令です．よって，x + y の計算結果を呼び出し元に返しています．つまり，変数 result には計算結果が代入されます．
Lua は複数の値を戻り値として返すことができます．例えば，次のようなことができます．
123function func()
return 10, 20
end

4
5

hoge, piyo = func()

6
7

print(hoge, piyo)
¶
実行結果

³

10 20

µ

´

hoge には 10 が，piyo には 20 が代入されます．
では，次のようなコードを書いた場合どうなるでしょうか．
1
2
3function func()
return 10, 20
end

4
5

hoge = func()

6
7

print(hoge, piyo)35

5.4 何も返さない関数
この場合，第 2 の戻り値である 20 は使われず消滅します．
¶
実行結果

³

10 nilµ´

また，次のようなコードを書いた場合はどうでしょうか．
1
2
3function func()
return 10
end

45

piyo = 20

67hoge, piyo = func()

8
9

print(hoge, piyo)

第 2 の戻り値はありません．この場合，piyo には nil が代入されます．piyo は 20ではないので注意してください．
¶
実行結果

³

10 nilµ5.4´

何も返さない関数

戻り値の関数，つまり何も返さない関数を作ることもできます．その場合 return
を書かなければ良いのです．
1
2
3function func()
print("関数が呼び出されました")
end

4
5

func()¶
実行結果³

関数が呼び出されましたµ´

また，明示的に戻り値が無いことを示すため，return だけを書くこともできます．

36

第 5 章 関数
1234function func()
print("関数が呼び出されました")
returnend

5
6

func()
上記の二つのコードは全く同じものです．

5.5

変数に関数を代入する

Lua の変数にはどんな値でも代入することができます．たとえ関数であろうとも代入が可能です．例えば次のようなことも可能です．
1
2
3function sum(x, y)
return x + y
end

4
5
6
7

function mul(x, y)
return x * y
end

8
9
10
11

hoge = sum
print("hoge is " .. type(hoge) );print("10 + 20 is " .. hoge(10, 20) )

12
13
14

hoge = mul
print("10 * 20 is " .. hoge(10, 20) )type 関数は現在の変数の型を調べるものでしたね．hoge には sum 関数や mul 関数を代入しています．そして，hoge を使い関数にアクセスすることもできます．C
言語をご存知の方は関数ポインタのようなことができると思ってください．
¶³
実行結果
hoge is function
10 + 20 is 30
10 * 20 is 200

µ

´

37

5.6 関数中に関数を定義する

5.6

関数中に関数を定義する

Lua では関数内に関数を定義することも可能です．
1
2
3
4

function func(x)local function get()return x
end

5local function add(value)x = x + value
end
return get, add

6
7
8
9
10

end

11
12
13

firstGetValue, firstAddValue = func(10)secondGetValue, secondAddValue = func(30)

14
15
16

print("first value : " .. firstGetValue() )print("second value : " .. secondGetValue() )

17
18
19

firstAddValue( 15 )secondAddValue( 20 )

20
21
22

print("first value : " .. firstGetValue() )print("second value : " .. secondGetValue() )func 関数は get と add 関数を戻り値として返しています．ここで local という新しいキーワードが登場しました．この local については有効範囲の章で詳しく説明
します．簡単に説明しておきますと，local というキーワードを付けることでローカル変数（またはローカル関数）を作成することができます．要は，get 関数も add
関数も func 関数内からでしか呼び出せないということです．
¶³
実行結果
first value : 10
second value : 30
first value : 25
second value : 50

µ

´

38

第 5 章 関数

5.7

無名関数

名前無し関数を作成することも可能です．例えば次のようなコードを書くことができます．
12345function createSquare()return function(x)return x*x
end
end

6
7
8

square = createSquare()print("10 * 10 is " .. square(10, 10) )createSquare 関数は戻り値に x*x を行う関数を返しています．
¶
実行結果

³

10 * 10 is 100

µ

5.8

´

標準ライブラリ

Lua には標準関数と呼ばれるものが存在します．これは，よく使われる処理があらかじめ関数として用意されています．例えば print 関数や io.read 関数などが標準関数にあたります．

5.8.1

基本ライブラリ

ここでは，基本ライブラリに用意されている関数の一部を紹介します．

assert 関数¶
定義³

assert (v [, message])µ´

assert 関数は v が偽条件ならばエラーを発生させる関数です．message にはエラーメッセージを渡します．エラーメッセージは省略可能です．

39

5.8 標準ライブラリ
1
2
3
4

hoge = true
assert( hoge, "Error #1")
hoge = false
assert( hoge, "Error #2")
¶
実行結果

³

lua51m.exe: test.lua:4: Error #2
stack traceback:[C]: in function ’assert’
test.lua:4: in main chunk[C]: ?
µ´

dofile 関数¶
定義³

dofile (filename)µ´

dofile 関数は filename で指定したファイルを実行する関数です．例えば以下のよ
うにして使います．今回は二つの Lua ファイル，test.lua と call.lua にコードを記述しています．
1
2
3
4
5
1
2

-- call.lua
function testFunc()
print ("Hello")
return "World!"end-- test.lua
dofile("call.lua")3
45hoge = testFunc()
print( hoge )
¶
実行結果

³

Hello
World!

µ´

dofile で call.lua を読み込む事により，test.lua 側で testFunc 関数を利用することができます．
40

第 5 章 関数

type 関数¶
定義³

type (v)µ´type 関数は，データの型を返す関数です．
1
2
3
4
5
6
7
8

hoge = nil
print("hoge : " .. type(hoge))hoge = 10
print("hoge : " .. type(hoge))hoge = true
print("hoge : " .. type(hoge))hoge = "Hello"
print("hoge : " .. type(hoge))
¶
実行結果

³

hoge : nil
hoge : number
hoge : boolean
hoge : stringµ´

tonumber 関数¶
定義³

tonumber (e [, base])µ´

tonumber 関数は引数 e を数値に変換する関数です．数値変換が可能な場合は数値を返し，そうでなければ nil を返します．
また，base を指定すると，e を base 進法の数値として変換します．省略すると，10 が自動的に指定されます．
1
2
3
4

hoge = "25"
print("hoge :" .. hoge .. " type :" .. type( hoge ) )piyo = tonumber( hoge )print("piyo :" .. piyo .. " type :" .. type(piyo) )41

5.8 標準ライブラリ
¶
実行結果

³

hoge :25 type :string
piyo :25 type :numberµ´

tostring 関数¶
定義³

tostring (e)µ´

tostring 関数は e を文字列に変換する関数です．
12
34hoge = 25
print("hoge :" .. hoge .. " type :" .. type( hoge ) )piyo = tostring( hoge )print("piyo :" .. piyo .. " type :" .. type(piyo) )
¶
実行結果

³

hoge :25 type :number
piyo :25 type :stringµ´

数値から文字列に変換する際は，わざわざ tostring 関数を使用しなくても，空の文字列を追加するだけでよいです．

piyo = hoge .. ""5.8.2

文字列操作ライブラリ

¶
定義

³

µ
¶
書式

´
³

µ

´

¶
実行結果

³

µ

´

42

43

第6章

C 言語との連携

この章では Lua と C 言語の連携について解説していきます.

6.1

Lua スタック

Lua と C 言語を連携させるためには，スタックの仕組みを理解しておかなければなりません．Lua から C 言語側にデータを渡す，または C 言語側から Lua にデー
タを渡す場合，Lua スタックと呼ばれるものを使用します．

6.1.1

スタックとは

図 6.1: スタック

スタック (Stack) は図 6.1 で表すようなデータ構造です．データは上から順に積
み上げられていきます．
スタックにデータを積み上げる動作をプッシュ(Push) するといいます．図 6.2 はスタックに値 10 をプッシュしている様子を表しています．
またスタックの上部のデータを一つ削除する動作をポップ (Pop) するといいます．図 6.3 はスタックから値をポップしている様子を表しています．

6.1 Lua スタック

図 6.2: 値のプッシュ

図 6.3: 値のポップ

44

第 6 章 C 言語との連携

6.1.2

Lua の初期化

次のコードは C 言語から Lua を利用するためのプログラムです．このプログラ
ムは Lua を初期化したあとは何もしません．
1#include <stdio.h>

2
3
4
5

#include "lua.h"#include "lualib.h"#include "lauxlib.h"

6
7
8
9

int main (void){
lua_State* L = luaL_newstate();10//ここに処理を書く

1112

lua_close(L);return 0;

13
14
15

}

Lua を呼び出すためには 3 つのヘッダファイル及び Lua の dll が必要です．
lua State は Lua インタプリタの状態全体を保持する不透明な構造体です．luaL newstate()関数を呼び出すと Lua の新しい状態を作り出し，Lua が利用可能な状態となりま
す．Lua を利用するためには必ずこの関数を呼び出すこととなります．
lua State 構造体である L の中には Lua インタプリタの現在の状態が保管されています．Lua を C 言語側から利用する際には必ず利用します．
また Lua を終了する場合は lua close() 関数を呼び出してください．この関数を呼び出すことでステート内で使われていたすべての動的メモリを解放します．

6.1.3

Lua スタックへ値をプッシュする

Lua スタックへ値をプッシュする場合，lua push***関数を呼び出します．***の部分にはデータ型が入ります．例えば boolean 型をプッシュする場合は boolean が，
number 型をプッシュする場合は number が入ります．
lua_pushboolean(L, 1);
lua_pushnumber(L, 10.5);
lua_pushinteger(L, 3);45

6.1 Lua スタック
lua_pushstring(L, "Hello world");
lua_pushnil(L);Lua 関係の関数は殆どの場合，第 1 引数に lua State を渡す必要があります．
1#include <stdio.h>

2
3
4
5

#include "lua.h"#include "lualib.h"#include "lauxlib.h"

6
7
8
9
10
11
12
13
14

void dumpStack(lua_State* L){
int i;//スタックに積まれている数を取得する
int stackSize = lua_gettop(L);for( i = stackSize; i >= 1; i-- ) {int type = lua_type(L, i);printf("Stack[%2d-%10s] : ", i, lua_typename(L,type) );

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

switch( type ) {case LUA_TNUMBER://number 型
printf("%f", lua_tonumber(L, i) );break;
case LUA_TBOOLEAN://boolean 型
if( lua_toboolean(L, i) ) {printf("true");}else{
printf("false");}break;
case LUA_TSTRING://string 型
printf("%s", lua_tostring(L, i) );break;
case LUA_TNIL:
//nil
46

第 6 章 C 言語との連携

break;

35

default:36//その他の型
printf("%s", lua_typename(L, type));break;

37
38
39}
printf("\n");

40
41

}
printf("\n");

42
43
44

}

45
46
47
48

int main (void){
lua_State* L = luaL_newstate();49

lua_pushboolean(L, 1); //true を push
dumpStack(L);lua_pushnumber(L, 10.5); //10.5 を push
dumpStack(L);lua_pushinteger(L, 3); //3 を push
dumpStack(L);lua_pushnil(L); //nil を push
dumpStack(L);lua_pushstring(L, "Hello world"); //hello world を push
dumpStack(L);

50
51
52
53
54
55
56
57
58
59
60

lua_close(L);return 0;

61
62
63

}
ここでは Lua スタックの状態を見るため dumpStack 関数を作成しました．この関数内の処理は現段階では理解しなくて結構です．
スタックの一番下は 1 番目となっています．値をプッシュするごとに 2 番目,3 番
目と積み重ねられていきます．dumpStack 関数はスタックの位置，スタックに格納されているデータ型，及びデータの中身を表示します．ただし，データの中身を表示できるのは，number,boolean,string,nil に限ります．

47

6.1 Lua スタック
¶
実行結果

³

Stack[ 1-boolean] : true

Stack[ 2Stack[ 1-number] : 10.500000
boolean] : true

Stack[ 3Stack[ 2Stack[ 1-number] : 3.000000
number] : 10.500000
boolean] : true

Stack[ 4Stack[ 3Stack[ 2Stack[ 1-nil] :
number] : 3.000000
number] : 10.500000
boolean] : true

Stack[ 5Stack[ 4Stack[ 3Stack[ 2Stack[ 1-string] : Hello world
nil] :
number] : 3.000000
number] : 10.500000
boolean] : true

µ

´

6.1.4

Lua スタックから値をポップする

Lua スタックから値をポップしてみましょう．値をポップするには lua pop() 関数を利用します．
lua_pop(L, 1); //上から 1 つ pop する
lua_pop(L, 2); //上から 2 つ pop する
1#include <stdio.h>

2
3
4
5

#include "lua.h"#include "lualib.h"#include "lauxlib.h"

6
7
8
9

void dumpStack(lua_State* L)
{
(略)
48

第 6 章 C 言語との連携
10

}

11
12
13
14

int main (void){
lua_State* L = luaL_newstate();15

lua_pushboolean(L, 1); //true を push
lua_pushnumber(L, 10.5); //10.5 を push
lua_pushinteger(L, 3); //3 を push
dumpStack(L);

16
17
18
19
20

lua_pop(L, 1); //値を 1 つ pop
dumpStack(L);

21
22
23

lua_pushnil(L); //nil を push
lua_pushstring(L, "Hello world"); //hello world を push
dumpStack(L);

24
25
26
27

lua_pop(L, 2); //値を 2 つ pop
dumpStack(L);

28
29
30

lua_close(L);return 0;

31
32
33

}

49

6.1 Lua スタック
¶
実行結果

³

Stack[ 3Stack[ 2Stack[ 1-number] : 3.000000
number] : 10.500000
boolean] : true

Stack[ 2Stack[ 1-number] : 10.500000
boolean] : true

Stack[ 4Stack[ 3Stack[ 2Stack[ 1-string] : Hello world
nil] :
number] : 10.500000
boolean] : true

Stack[ 2Stack[ 1-number] : 10.500000
boolean] : true

µ

´

6.1.5

Lua スタックの操作

スタック操作系の関数を紹介します．

int lua_gettop(lua_State* L);
void lua_settop(lua_State* L, int index);
void lua_pushvalue(lua_State* L, int index);
void lua_remove(lua_State* L, int index);
void lua_insert(lua_State* L, int index);
void lua_replace(lua_State* L, int index);
lua gettop 関数はスタックに積まれている数を取得します (図 6.4)．
lua settop 関数はスタックに積まれている値の数を変更します (図 6.5)．スタッ
クの値を削除（ポップ）するのに使われています．
index には変更後のスタックの数を指定します．ただし，マイナスの index は上から積まれたスタックの数を表しています (図 6.6)．
つまり，
lua_settop(L, -1); //一番上のスタックは一番上のスタックまで残すという意味です．つまりこの操作をしてもスタックには変化がありません．スタックを操作する時にはマイナスの index を指定する方法がよく使われます．
スタックを空にするには index に 0 を指定します．

50

第 6 章 C 言語との連携

図 6.4: lua gettop 関数

図 6.5: lua settop 関数

図 6.6: lua settop 関数516.1 Lua スタック
lua_settop(L, 0); //スタックをすべて削除
スタックの値をポップする場合は lua pop 関数を利用しましたが (図 6.7)，この関数は実は lua settop 関数のマクロとなっています．

#define lua_pop(L, n)

lua_settop(L, -(n) - 1)

図 6.7: lua pop 関数

lua pushvalue 関数は指定した index の値をコピーしてスタックにプッシュしま
す (図 6.8)．

図 6.8: lua pushvalue 関数

lua remove 関数は指定した index の値を削除します (図 6.9)．要素を削除したら，指定した index の上に乗っていた要素をずらして隙間を埋めます．
lua insert 関数はスタックの一番上にある要素を指定した index に挿入します (図6.10)．
52

第 6 章 C 言語との連携

図 6.9: lua remove 関数

図 6.10: lua insert 関数

図 6.11: lua replace 関数536.1 Lua スタック
lua replace 関数はスタックの一番上の要素を指定した index に置き換えます (図6.11)．
スタック操作系の関数のサンプルコードをお見せします．
1#include <stdio.h>

2
3
4
5

#include "lua.h"#include "lualib.h"#include "lauxlib.h"

6
7
8
9
10

void dumpStack(lua_State* L)
{
(略)
}

11
12
13
14

int main (void){
lua_State* L = luaL_newstate();

15
16
17
18
19
20

lua_pushnumber(L, 10); //10 push
lua_pushnumber(L, 20); //20 push
lua_pushnumber(L, 30); //30 push
lua_pushnumber(L, 40); //40 push
dumpStack(L);

21
22
23

//スタックの要素数取得
printf("現在のスタックの数 : %d\n", lua_gettop(L));

24
25
26
27
28

//上から 3 つ目の要素をコピーしてスタックに積む
printf("pushvalue -3\n");lua_pushvalue(L, -3);
dumpStack(L);

29
30
31
32
33

//上から 3 つ目の要素を削除する
printf("remove -3\n");lua_remove(L, -3);
dumpStack(L);34
35//スタックトップの値を 2 番目に挿入する
54

第 6 章 C 言語との連携

printf("insert 2\n");lua_insert(L, 2);
dumpStack(L);

36
37
38
39

//スタックトップの値を 2 番目の要素とする
printf("replace 2\n");lua_replace(L, 2);
dumpStack(L);

40
41
42
43
44

lua_close(L);return 0;

45
46
47

}

55

6.1 Lua スタック¶
実行結果

Stack[ 4Stack[ 3Stack[ 2Stack[ 1-³number] : 40.000000
number] : 30.000000
number] : 20.000000
number] : 10.000000

現在のスタックの数 : 4
pushvalue -3
Stack[ 5number] : 20.000000
Stack[ 4number] : 40.000000
Stack[ 3number] : 30.000000
Stack[ 2number] : 20.000000
Stack[ 1number] : 10.000000

remove -3
Stack[ 4Stack[ 3Stack[ 2Stack[ 1-number] : 20.000000
number] : 40.000000
number] : 20.000000
number] : 10.000000

insert 2
Stack[ 4Stack[ 3Stack[ 2Stack[ 1-number] : 40.000000
number] : 20.000000
number] : 20.000000
number] : 10.000000

replace 2
Stack[ 3Stack[ 2Stack[ 1-number] : 20.000000
number] : 40.000000
number] : 10.000000

µ

6.1.6

´

Lua スタックのサイズ

Lua スタックに値を積むことができる数には上限があります．スタックサイズの上限を超えて値を積むとスタックオーバーフローとなってしまいます．通常は
LUA MINSTACK 個 (20 に設定されている) だけスタックに値を積むことができます．普通に使う分にはスタックの容量を気にする必要はないですが，もし大量の56

第 6 章 C 言語との連携
値を積みたい場合は注意が必要です．
次のサンプルコードはスタックオーバーフローが発生する例です．
1#include <stdio.h>

2
3
4
5

#include "lua.h"#include "lualib.h"#include "lauxlib.h"

6
7
8
9
10
11

int main (void){//このコードはエラーが発生する
int i=0;
lua_State* L = luaL_newstate();12

for(i=0; i < 100; i++) {lua_pushnumber(L, i + 1);}
lua_close(L);return 0;

13
14
15
16
17

}

18

スタックの容量を増やすには lua checkstack 関数を使用します．

int lua_checkstack (lua_State* L, int extra)
この関数はスタックに extra 個の値の空きがあることを保障するための関数です．
つまりスタックの容量を伸ばすための関数です．extra 個だけ値を積むことができることが保障できれば true(=1) を返し，そうでなければ false(=0) を返します．
先ほどのエラーが発生したコードに lua checkstack 関数を加えると正常に動作します．
1#include <stdio.h>

2
3
4
5

#include "lua.h"#include "lualib.h"#include "lauxlib.h"6
78void dumpStack(lua_State* L){57

6.1 Lua スタック
(略)

9

}

10
11

int main (void){
int i=0;
lua_State* L = luaL_newstate();

12
13
14
15
16

if( lua_checkstack(L, 100) == 0 ) {printf("スタックの容量が確保できませんでした\n");return 1;
}

17
18
19
20
21

for(i=0; i < 100; i++) {lua_pushnumber(L, i + 1);}
dumpStack(L);lua_close(L);return 0;

22
23
24
25
26
27
28

}
¶
実行結果

Stack[100Stack[99(略)Stack[ 3Stack[ 2Stack[ 1-³number] : 100.000000
number] : 99.000000
number] : 3.000000
number] : 2.000000
number] : 1.000000

µ

´

6.1.7

Lua スタックの値の参照

スタックに積まれている値の型を見るには lua type 関数を使用します．

int lua_type (lua_State* L, int index)
この関数は指定した index の型を返します（表 6.1）．lua type が返す型は lua.h内で定義されています．有効でない index が渡された場合は LUA TNONE を戻り値として返します．

58

第 6 章 C 言語との連携

表 6.1: lua type 関数の戻り値
型
戻り値
nil
LUA TNIL
number
LUA TNUMBER
boolean
LUA TBOOLEAN
string
LUA TSTRING
table
LUA TTABLE
function
LUA TFUNCTION
userdata
LUA TUSERDATA
threadLUA TTHREAD
lightuserdata LUA TLIGHTUSERDATA

また，指定した型かどうかを判定する lua is***関数も存在しています．***の部
分には型が入ります．

int lua_is*** (lua_State* L, int index)
例えば index で指定したスタックの要素が boolean かを判定したい場合は，

int lua_isboolean (lua_State* L, int index)とします．返却値が true，つまり 1 であれば boolean であり，false, つまり 0 が返されれば boolean 型ではないということになります．これらの関数は実は lua type関数を利用したマクロとなっています．
また，指定した index の要素を指定した型で取得する関数 lua to***関数も存在します．***の部分には型が入ります．

int lua_to*** (lua_State* L, int index)

6.1.8

Lua スタック上のテーブルの格納と参照

Lua スタック上のテーブルの値を書き換えたり参照したりすることもできます．
void lua_settable (lua_State *L, int index);
void lua_setfield (lua_State *L, int index, const char *k);void lua_gettable (lua_State *L, int index);
void lua_getfield (lua_State *L, int index, const char *k);59

6.1 Lua スタック
スタック上に存在しているテーブルにキーと値を格納するには lua settable 関数
か lua setfield 関数を使用します．
lua settable 関数はスタックトップには格納する値を，スタックトップの一つ下にはキーとなる値を入れておき，これらのペアを index で指定したテーブルに格納します（図 6.12）．また，スタックに積まれていたキーと値はスタック上から削除されます．

図 6.12: lua settable 関数

lua setfield 関数はキーを関数側から指定できます．スタックトップには格納したい値を積んでおきます．この関数は lua settable 関数とは違い，キーには文字列しか指定できません（図 6.13）．

図 6.13: lua setfield 関数

lua gettable 関数は index で指定したテーブルからキーと対になっている値を取得しスタックに積みます．キーはスタックトップに積んでおきます（図 6.14）．

60

第 6 章 C 言語との連携

図 6.14: lua gettable 関数

lua getfield 関数はキーを関数側から指定できます．この関数も lua gettable 関
数とは違い，キーには文字列しか指定できません（図 6.15）．

図 6.15: lua getfield 関数

テーブルは C 言語側から作成することができます．空のテーブルを作成したい場合は lua newtable 関数を呼び出します（図 6.16）．

void lua_newtable (lua_State *L);
この関数は実は lua createtable 関数のマクロとなっています．

void lua_createtable (lua_State *L, int narr, int nrec);61

6.1 Lua スタック

図 6.16: lua createtable 関数

引数 narr には配列要素の個数を，nrec には非配列要素の個数を指定します．この個数を指定するとあらかじめ割り当て済みの空間が与えられます．要はテーブ
ルがたくさん要素を持つことがあらかじめ分かっている場合に役にたつ関数です．
lua_newtable(L) は lua_createtable(L, 0, 0) とマクロで定義されています．
通常テーブルを作る際は lua newtable 関数で十分です．
以上の関数を使ったサンプルコードをお見せします．
1#include <stdio.h>

2
3
4
5

#include "lua.h"#include "lualib.h"#include "lauxlib.h"

6
7
8
9
10

void dumpStack(lua_State* L)
{
(略)
}

11
12
13
14
15

int main (void){
int i=0;
lua_State* L = luaL_newstate();

16
17
18
19

lua_newtable(L); //新しい table の作成
lua_pushnumber(L, 10); //key
lua_pushstring(L, "hello"); //value62

第 6 章 C 言語との連携

dumpStack(L);2021// table[10] = "hello" を実行
lua_settable(L, -3);
dumpStack(L);

22
23
24
25

//value
lua_pushstring(L, "world");//table["key"] = "world" を実行
lua_setfield(L, -2, "key");
dumpStack(L);

26
27
28
29
30
31

lua_pushnumber(L, 10);//table[10] の値を取り出しスタックに積む
lua_gettable(L, -2);
dumpStack(L);

32
33
34
35
36

//table["key"] の値を取り出しスタックに積む
lua_getfield(L, -2, "key");
dumpStack(L);

37
38
39
40

lua_close(L);return 0;

41
42
43

}

63

6.2 C から Lua を呼び出す
¶
実行結果

³

Stack[ 3Stack[ 2Stack[ 1-string] : hello
number] : 10.000000
table] : table

Stack[ 1-table] : table

Stack[ 1-table] : table

Stack[ 2Stack[ 1-string] : hellotable] : table

Stack[ 3Stack[ 2Stack[ 1-string] : world
string] : hellotable] : table

µ

6.2

´

C から Lua を呼び出す

この節では C 言語側から Lua の変数や関数を呼び出す方法を説明していきます．

6.2.1

Lua ファイルを読み込む

まずは C 言語側から Lua で書かれたコードを読み込んでみましょう．次のような Lua ソースコードを作成したとします．このコードのファイル名は sample.lua
です．
1--sample.lua

23--グローバル変数

4
5
6

NAME = "HELLOWORLD"SIZE = 640
この Lua ファイルを読み込むための C 言語コードは以下のようになります．

1#include <stdio.h>23#include "lua.h"64

第 6 章 C 言語との連携
4
5#include "lualib.h"#include "lauxlib.h"

6
7
8
9
10
11
12
13
14
15
16
17
18
19

int main (void){//Lua を開く
lua_State* L = luaL_newstate();//Lua の標準関数を使用できる状態にする
luaL_openlibs(L);//Lua ファイル sample.lua を読み込む
if( luaL_loadfile(L, "sample.lua") || lua_pcall(L, 0, 0, 0) ) {printf("sample.lua を開けませんでした\n");printf("error : %s\n", lua_tostring(L, -1) );return 1;}//ここに何か処理を書く

20

lua_close(L);return 0;

21
22
23

}
このプログラムは sample.lua を読み込むだけで何も処理は行いません．
ここで新たに 3 つの新しい関数が登場しました．まず，luaL openlibs 関数ですが，この関数は Lua 内で標準関数が利用できるようにするものです．この関数を呼び出さないと Lua 内で print 関数などが使用できません．
luaL loadfile 関数ですが，次のような定義となっています．

int luaL_loadfile (lua_State *L, const char *filename);filename には開きたい Lua ファイルを指定します．この関数はファイルが読み込めなかった場合（ファイルが存在しない，文法が間違っていた等），LUA ERRFILEを返します．
lua pcall 関数ですが，この関数は本来 Lua の関数を呼ぶためのものです．ここでは使い方を詳しく説明しませんが，loadfile を行った後ファイルを実行する役目を果たしています．
luaL openlibs 関数及び lua pcall 関数は成功すると 0 を返します．この戻り値を使ってファイルが正しく読み込めたかどうかを判定できます．また，エラーが発生した場合，エラーの詳細をスタックに積んでくれます．よってスタックトップの値を参照すればエラーの原因を特定できます．
65

6.2 C から Lua を呼び出す
では，試しに luaL loadfile 関数の引数に sample.lua ではなく存在しないファイル test.lua を指定してみましょう．結果は以下のようになります．
¶
実行結果

³

sample.lua を開けませんでした
error : cannot open test.lua: No such file or directoryµ´

また Lua ファイルの 2 行目に適当な文法の文字列を挿入してみます．挿入した文字列は if a-b=c then end です．
¶
実行結果

³

sample.lua を開けませんでした
error : sample.lua:2: ’then’ expected near ’=’
µ

6.2.2

´

Lua のグローバル変数を取得する

前節で登場した sample.lua から変数 NAME と SIZE の値を取得してみましょう．
NAME は文字列で取得し，SIZE は NUMBER で取得します．
1#include <stdio.h>

2
3
4
5

#include "lua.h"#include "lualib.h"#include "lauxlib.h"

6
7
8
9
10
11
12
13
14
15
16
17
18

int main (void){//Lua を開く
lua_State* L = luaL_newstate();//Lua の標準関数を使用できる状態にする
luaL_openlibs(L);//Lua ファイル sample.lua を読み込む
if( luaL_loadfile(L, "sample.lua") || lua_pcall(L, 0, 0, 0) ) {printf("sample.lua を開けませんでした\n");printf("error : %s\n", lua_tostring(L, -1) );return 1;}

19
20//PATH を取得しスタックに積む66

第 6 章 C 言語との連携

lua_getglobal(L, "NAME");//SIZE を取得しスタックに積む
lua_getglobal(L, "SIZE");

21
22
23
24

if( !lua_isstring(L, -2) || !lua_isnumber(L, -1) ) {printf("正しく値が取得できませんでした\n");return 1;}
printf("NAME : %s\n", lua_tostring(L, -2));
printf("SIZE : %d\n", lua_tointeger(L, -1));

25
26
27
28
29
30
31

lua_close(L);return 0;

32
33

}

34

¶
実行結果

³

NAME : HELLOWORLDSIZE : 640µ´lua getglobal 関数はグローバル変数を取得する変数で以下のように定義されています．
void lua_getglobal (lua_State *L, const char *name);name には取得したいグローバル変数の変数名を指定します．実はこの関数は
lua gettable 関数のマクロとなっています．
#define lua_getglobal(L,s)

lua_getfield(L, LUA_GLOBALSINDEX, s)

LUA GLOBALSINDEX は Lua のグローバル変数がある領域テーブルを指しています．
さて，上記のサンプルですがスタックには NAME と SIZE が残ったままになっています．実際のプログラムでは NAME,SIZE を使用したあとはきちんとポップ
しておきましょう．

6.2.3

Lua 関数を呼び出す

C 言語側から Lua の関数を呼び出してみましょう．次のような add 関数を Luaで作成したとします．ファイル名は sample.lua です．
67

6.2 C から Lua を呼び出す
1--sample.lua

2
3
4
5
6

function add(x, y)
print("x : ".. x .. " y : " .. y .. "を受け取りました")
return x + y
end

add 関数は二つの引数 x,y を受け取り，その合計値を返却します．では C 言語側のサンプルコードをお見せします．
1#include <stdio.h>

2
3
4
5

#include "lua.h"#include "lualib.h"#include "lauxlib.h"

6
7
8
9

int main (void){
int x = 10, y = 5;

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

//Lua を開く
lua_State* L = luaL_newstate();//Lua の標準関数を使用できる状態にする
luaL_openlibs(L);//Lua ファイル sample.lua を読み込む
if( luaL_loadfile(L, "sample.lua") || lua_pcall(L, 0, 0, 0) ) {printf("sample.lua を開けませんでした\n");printf("error : %s\n", lua_tostring(L, -1) );return 1;}//add 関数をスタックに積む
lua_getglobal(L, "add");//第 1 引数 x
lua_pushnumber(L, x);//第 2 引数 ylua_pushnumber(L, y);

27
28
29

//add(x, y) を呼び出す 引数 2 個，戻り値 1 個
if(lua_pcall(L, 2, 1, 0) != 0) {68

第 6 章 C 言語との連携

printf("関数呼び出し失敗\n");printf("error : %s\n", lua_tostring(L, -1) );return 1;

30
31
32

}
if( lua_isnumber(L, -1) ) {printf("結果 : %d\n", lua_tointeger(L, -1) );lua_pop(L,1); //戻り値をポップ
}

33
34
35
36
37
38

lua_close(L);return 0;

39
40
41

}
¶
実行結果

³

x : 10 y : 5 を受け取りました
結果 : 15µ´

ここで登場した関数が lua pcall 関数です（図 6.17）．

図 6.17: lua pcall 関数

この関数は次のように定義されています．

lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);
nargs には関数に渡す引数の数を，nresults は関数から受け取る戻り値の数を指定します．errfunc は通常は 0 のままでかまいません．
さて，関数を呼ぶには次のような手順が必要です．まず，始めに呼び出したい関数を取得しスタックに積みます．次にその関数に渡す引数を順番どおりに積んでいきます．つまり第 1 引数は一番初めにプッシュしなければなりません．そして lua pcall を呼び出すとその関数を実行します．関数を呼び出した後は，スタッ69

6.2 C から Lua を呼び出す
クに積まれていた関数，及び引数はスタック上から削除されます．関数からの戻り値がある場合は戻り値の順番どおり，つまり最初の戻り値は最初にスタックに積まれていきます．
また，lua pcall 関数は関数の呼び出しに失敗するとエラーコードをスタックに
積みます．

6.2.4

Lua にグローバル変数を登録する

C 言語側から Lua のグローバル変数を登録してみましょう．ここでは TEST という変数（値は 10 とする）を登録してみます．
まずは次のようなコード，sample.lua を作ります．
1--sample.lua

2
3
4
5
6
7
8
9

function show()
if TEST == nil thenprint("TEST は登録されていません")
else
print("TEST の値は" .. TEST .. "です")
end
end
そして C 言語側のコードは次のようになります．

1#include <stdio.h>

2
3
4
5

#include "lua.h"#include "lualib.h"#include "lauxlib.h"

6
7
8
9
10
11
12
13
14
15

void showTest(lua_State* L){//show 関数をスタックに積む
lua_getglobal(L, "show");//show 関数を呼び出す 引数 0 個, 戻り値 0 個
if(lua_pcall(L, 0, 0, 0) != 0) {printf("関数呼び出し失敗\n");printf("error : %s\n", lua_tostring(L, -1) );lua_pop(L, 1);
70

第 6 章 C 言語との連携

}

16

}

17
18

int main (void){
int x = 10, y = 5;

19
20
21
22

//Lua を開く
lua_State* L = luaL_newstate();//Lua の標準関数を使用できる状態にする
luaL_openlibs(L);//Lua ファイル sample.lua を読み込む
if( luaL_loadfile(L, "sample.lua") || lua_pcall(L, 0, 0, 0) ) {printf("sample.lua を開けませんでした\n");printf("error : %s\n", lua_tostring(L, -1) );return 1;
}

23
24
25
26
27
28
29
30
31
32
33

//Lua の show 関数を呼び出す
showTest(L);//変数 TEST(値は 10) を Lua に登録
lua_pushnumber(L, 10);
lua_setglobal(L, "TEST");//TEST 表示
showTest(L);

34
35
36
37
38
39
40
41

lua_close(L);return 0;

42
43
44

}
¶
実行結果

³

TEST は登録されていません
TEST の値は 10 ですµ´

Lua の show 関数を呼び出すための C 言語関数 showTest を作成しました．1 回
目に show 関数が呼び出された時は，変数 TEST はまだ存在しないので nil となっています．2 回目に呼び出された時は，C 言語側から TEST=10 として登録されているので，値が表示されます．
さて，グローバル変数を登録するには lua setglobal 関数を使用します．
71

6.3 Lua から C を呼び出す
void lua_setglobal (lua_State *L, const char *name);
この関数はスタックトップの値を name として Lua に登録します．実は lua setglobal
関数は lua setfield 関数のマクロとして定義されています．

#define lua_setglobal(L,s)

6.3

lua_setfield(L, LUA_GLOBALSINDEX, s)

Lua から C を呼び出す

この節では Lua 側から C の関数を呼び出す方法について説明していきます．

6.3.1

C 関数を呼び出す

Lua 側から C 言語の関数 add を呼び出してみます．
Lua 側では次のようなソースを書いたとします．Lua ファイル名は sample.lua
です．
1--sample.lua

2
3
4
5

x,y = 5, 10
result = add(x, y)
print("x + y は " .. result .. " です")では C 言語側の関数をお見せします．

1#include <stdio.h>

2
3
4
5

#include "lua.h"#include "lualib.h"#include "lauxlib.h"

6
7
8
9
10
11
12
13

int l_add(lua_State* L){//第 1 引数 int として取得
int x = luaL_checkint(L, -2);//第 2 引数int y = luaL_checkint(L, -1);
int result = x + y;

14

72

第 6 章 C 言語との連携

printf("%d + %d を計算します\n", x, y);1516//戻り値をスタックに積む
lua_pushnumber(L, result);
return 1; //戻り値の数を指定

17
18
19

}

20
21

int main (void){
int x = 10, y = 5;

22
23
24
25

//Lua を開く
lua_State* L = luaL_newstate();//Lua の標準関数を使用できる状態にする
luaL_openlibs(L);

26
27
28
29
30

//l_add 関数を add 関数として Lua に登録
lua_register(L, "add", l_add);

31
32
33

//Lua ファイル sample.lua を読み込む
if( luaL_loadfile(L, "sample.lua") || lua_pcall(L, 0, 0, 0) ) {printf("sample.lua を開けませんでした\n");printf("error : %s\n", lua_tostring(L, -1) );return 1;
}

34
35
36
37
38
39
40

lua_close(L);return 0;

41
42
43

}
¶
実行結果

³

5 + 10 を計算します
x + y は 15 ですµ´

Lua 側で C 言語関数を呼び出すと，l add 関数の Lua スタックに引数が積まれます．C 言語側の引数に直接値が渡されるわけではないので注意してください．第 1
引数は始めにプッシュされ，第 2 引数はその次にプッシュされます．よって C 言
語側からこのスタックの値を取得すればよいわけです．
736.3 Lua から C を呼び出す
スタックの値を取得する時に luaL check***関数を使用しました．***には Lua
変数のデータ型が入ります．この関数は指定したスタックの値を***型であるかを判定してから取得します．もし***型で無かった場合はエラーが発生します．
試しに add 関数の第 1 引数に文字列を渡してみました．結果は以下のようにな
りました．
¶
実行結果

³

sample.lua を開けませんでした
error : sample.lua:4: bad argument #-2 to’add’ (number expected, got string)µ´

l add 関数から戻り値を返す場合も Lua スタックに値を積みます．l add 関数の戻り値には戻り値の数を指定します．
さて，Lua 側から C 関数を呼び出すためには，Lua に関数を登録しなければな
りません．その際使用するのが lua register 関数です．
void lua_register (lua_State *L, const char *name, lua_CFunction f);name には Lua から呼び出す関数名を登録します．f には C 言語関数を渡します．
実はこの関数は以下のようにマクロとなっています．
#define lua_register(L,n,f)(lua_pushcfunction(L, f), lua_setglobal(L, n))lua pushcfunction 関数は C 言語関数 f をスタックにプッシュするものです．

6.3.2

関数毎の Lua スタック

前節の l add 関数のスタック上の値について考えて見ましょう．l add 関数を呼び出した後の Lua スタックには引数 x,y や戻り値 result が残ったままになっているでしょうか．もし残ったままならポップしなければいけないのかという疑問が残っています．
ここで次のようなコードを作ってみます．前節でも登場した dumpStack 関数を使用しています．
1#include <stdio.h>

2
3
4
5

#include "lua.h"#include "lualib.h"#include "lauxlib.h"674

第 6 章 C 言語との連携
7
8
9
10
11
12
13
14

void dumpStack(lua_State* L){
int i;//スタックに積まれている数を取得する
int stackSize = lua_gettop(L);for( i = stackSize; i >= 1; i-- ) {int type = lua_type(L, i);printf("Stack[%2d-%10s] : ", i, lua_typename(L,type) );15

switch( type ) {case LUA_TNUMBER://number 型
printf("%f", lua_tonumber(L, i) );break;
case LUA_TBOOLEAN://boolean 型
if( lua_toboolean(L, i) ) {printf("true");}else{
printf("false");}break;
case LUA_TSTRING://string 型
printf("%s", lua_tostring(L, i) );break;
case LUA_TNIL://nil
break;
default://その他の型
printf("%s", lua_typename(L, type));break;}
printf("\n");

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

}
printf("\n");

42
43
44

}
75

6.3 Lua から C を呼び出す
45
46
47
48
49
50
51
52

int l_add(lua_State* L){//第 1 引数 int として取得
int x = luaL_checkint(L, -2);//第 2 引数int y = luaL_checkint(L, -1);
int result = x + y;53

printf("%d + %d を計算します\n", x, y);5455//戻り値をスタックに積む
lua_pushnumber(L, result);

56
57
58

//ダンプ 2 箇所目
printf("2 番目\n");dumpStack(L);

59
60
61
62

return 1; //戻り値の数を指定

63
64

}

65
66
67
68

int main (void){
int x = 10, y = 5;

69
70
71
72
73

//Lua を開く
lua_State* L = luaL_newstate();//Lua の標準関数を使用できる状態にする
luaL_openlibs(L);

74
75
76

//l_add 関数を add 関数として Lua に登録
lua_register(L, "add", l_add);

77
78
79
80

//適当な値をプッシュ
lua_pushnumber(L, 444);
lua_pushnumber(L, 555);

81
82//ダンプ 1 箇所目
76

第 6 章 C 言語との連携

printf("1 番目\n");dumpStack(L);

83
84
85

//Lua ファイル sample.lua を読み込む
if( luaL_loadfile(L, "sample.lua") || lua_pcall(L, 0, 0, 0) ) {printf("sample.lua を開けませんでした\n");printf("error : %s\n", lua_tostring(L, -1) );return 1;
}

86
87
88
89
90
91
92

//ダンプ 1 箇所目
printf("3 番目\n");dumpStack(L);

93
94
95
96

lua_close(L);return 0;

97
98

}

99

3 箇所から dumpStack 関数を呼び出しています．さて，実行結果は以下の通りとなりました．
¶
³
実行結果
1 番目
Stack[ 2Stack[ 1-number] : 555.000000
number] : 444.000000

5 + 10 を計算します
2 番目
Stack[ 3number] : 15.000000
Stack[ 2number] : 10.000000
Stack[ 1number] : 5.000000
x + y は 15 です
3 番目
Stack[ 2number] : 555.000000
Stack[ 1number] : 444.000000µ´

実は Lua スタックは関数ごとに用意されています．つまり，l add 関数からはmain 関数側のスタックは見えないわけです．また，l add 関数のスタックは Lua が77

6.3 Lua から C を呼び出す
勝手に削除してくれます．よって，l add 関数上のスタックはわざわざポップする
必要はありません．

6.3.3

テーブルに C 言語関数を登録する

前節では，関数をグローバル関数として定義しました．しかし，関数が増えてくると名前の衝突などが起こってしまう場合があります．そういった事態を避けるため，テーブル内に関数を定義するといった方法が取られます．
次のようなサンプルコードを書いてみます．まずは Lua 側のコードです．
1--sample.lua

2
3
4
5

x, y = 5, 10
print( x .. " + " .. y .. " = " .. myMath.add(x, y) )print( x .. " * " .. y .. " = " .. myMath.mul(x, y) )myMath テーブルにある add 関数と mul 関数を呼び出しています．
では，テーブルに関数を登録する C のサンプルコードをお見せします．

1#include <stdio.h>

2
3
4
5

#include "lua.h"#include "lualib.h"#include "lauxlib.h"

6
7
8
9
10
11
12
13

int l_add(lua_State* L){//第 1 引数 int として取得
int x = luaL_checkint(L, -2);//第 2 引数int y = luaL_checkint(L, -1);
int result = x + y;

14
15

printf("%d + %d を計算します\n", x, y);

16
17
18

//戻り値をスタックに積む
lua_pushnumber(L, result);

19
20

return 1; //戻り値の数を指定
78

第 6 章 C 言語との連携
21

}

22
23
24
25
26
27
28
29

int l_mul(lua_State* L){//第 1 引数 int として取得
int x = luaL_checkint(L, -2);//第 2 引数int y = luaL_checkint(L, -1);
int result = x * y;30

printf("%d * %d を計算します\n", x, y);3132//戻り値をスタックに積む
lua_pushnumber(L, result);

33
34
35

return 1; //戻り値の数を指定

36
37

}

38
39
40
41
42
43
44

//登録する関数
static const struct luaL_Reg myMathLib [] = {{"add", l_add},{"mul", l_mul},{NULL, NULL} //最後は必ず NULL のペア
};

45
46
47
48

int main (void){
int x = 10, y = 5;

49
50
51
52
53

//Lua を開く
lua_State* L = luaL_newstate();//Lua の標準関数を使用できる状態にする
luaL_openlibs(L);

54
55
56

//add, mul を myMath テーブルに登録
luaL_register(L, "myMath", myMathLib);

57
58//Lua ファイル sample.lua を読み込む
79

6.3 Lua から C を呼び出す
if( luaL_loadfile(L, "sample.lua") || lua_pcall(L, 0, 0, 0) ) {printf("sample.lua を開けませんでした\n");printf("error : %s\n", lua_tostring(L, -1) );return 1;
}

59
60
61
62
63
64

lua_close(L);return 0;

65
66
67

}
¶
実行結果

³

5 + 10 を計算します
5 + 10 = 15
5 * 10 を計算します
5 * 10 = 50µ´luaL reg 構造体は以下のように定義されています．
typedef struct luaL_Reg {const char *name;lua_CFunction func;} luaL_Reg;name 側には Lua 側に登録したい関数名を，func には C 言語関数を渡します．
myMath テーブルを新たに作成し，luaL reg 構造体で定義した関数を登録する
ためには luaL register 関数を使用します．

80