Fungsi-Fungsi Pada C

26.1 Fungsi-Fungsi Pada C

Sebagai contoh pertama, Mari kita lihat bagaimana cara untuk menerapkan versi yang disederhanakan dari sebuah fungsi yang mengembalikan sin dari bilangan yang telah diberikan (penerapan yang lebih professional harus dapat memeriksa apakah argumentasinya berupa bilangan).

static int l_sin (lua_State *L) { double d = lua_tonumber(L, 1); /* get argument */ lua_pushnumber(L, sin(d)); /* push result */ return 1; /* number of results */ }

Setiap fungsi yang di-register dengan Lua harus mempunyai prototype (model) yang sama, didefinisikan sebagai lua_CFunction di dalam lua.h :

typedef int (*lua_CFunction) (lua_State *L);

Dilihat dari sudut pandang C, sebuah fungsi C hanya mendapatkan status Lua sebagai argument tunggal dan mengembalikannya (pada C) sebagai bilangan bulat (integer) dengan nilai yang dikembalikan dari fungsi tersebut (pada Lua). Oleh karena itu, fungsi tidak harus membersihkan stack sebelum mendorong hasilnya. Setelah proses kembali, Lua secara otomatis memindahkan apapun juga yang ada di dalam stack di bawah hasil.

Sebelum kita menggunakan fungsi ini dari Lua, kita harus mendaftarkannya(register) terlebih dahulu. Kita dapat melakukannya dengan lua_pushcfunction. Dengan cara ini kita akan mendapatkan sebuah pointer menuju sebuah fungsi C dan membuat sebuah nilai dari tipe “function” untuk menghadirkan fungsi ini di dalam Lua. Cara yang cepat dan curang untuk melakukan tes 1_sin adalah untuk meletakan kode tersebut secara langsung ke dalam file lua .c dan menambah baris-baris yang mengikuti tepat setelah memanggil lua_open :

lua_pushcfunction(l, l_sin); lua_setglobal(l, "mysin");

Baris pertama mendorong sebuah nilai dari function. Baris kedua menugaskannya ke variabel global mysin. Setelah modifikasi ini, anda dapat membangun kembali Lua executable, kemudian anda dapat menggunakan fungsi baru mysin di dalam program Lua anda. Pada bagian selanjutnya, kita akan membicarakan cara-cara yang lebih baik untuk menghubungkan fungsi- fungsi C dengan Lua.

Untuk fungsi sin yang lebih professional, kita harus memeriksa tipe-tipe argumentasinya. Di sini, library dapat membantu kita. Fungsi luaL_checknumber memeriksa apakah argumen yang diberikan adalah berupa bilangan. Pada kasus error, fungsi tersebut memberikan sebuah error message yang informatif, dengan cara lain, fungsi mengembalikan bilangan - bilangan tersebut. Modifikasi di dalam fungsi kita adalah minimal :

static int l_sin (lua_State *L) { double d = luaL_checknumber(L, 1); lua_pushnumber(L, sin(d)); return 1; /* number of results */ }

Dengan definisi di atas, jika anda memanggil mysin (‘a’), anda akan mendapat pesan (message) :

bad argument #1 to `mysin' (number expected, got string)

Perlu diperhatikan bagaimana luaL_checknumber mengisi pesan secara otomatis dengan nomor argumentasi (1), nama fungsi ( “mysin”), tipe parameter yang diterima ( “number”), dan tipe parameter yang sebenarnya (“string”).

Sebagai contoh yang lebih rumit, mari kita menuliskan sebuah fungsi yang mengembalikan isi dari direktori yang telah diberikan. Lua tidak menghasilkan fungsi ini di dalam library standarnya, karena ANSI tidak memiliki fungsi-fungsi untuk pekerjaan ini. Di sini, kita akan berasumsi bahwa kita memiliki suatu system yang memenuhi POSIX. Fungsi yang dapat kita gunakan, dir, mengambil string sebagai argument dengan path directory dan mengembalikan

sebuah array dengan directory entries. Sebagai contoh, sebuah panggilan dir("/home/lua") dapat mengembalikan table {".", "..", "src", "bin", "lib"}. Pada kasus error, sebuah array dengan directory entries. Sebagai contoh, sebuah panggilan dir("/home/lua") dapat mengembalikan table {".", "..", "src", "bin", "lib"}. Pada kasus error,

#include <dirent.h> #include <errno.h>

static int l_dir (lua_State *L) { DIR *dir; struct dirent *entry; int i; const char *path = luaL_checkstring(L, 1);

/* open directory */ dir = opendir(path); if (dir == NULL) { /* error opening the directory? */

lua_pushnil(L); /* return nil and ... */ lua_pushstring(L, strerror(errno)); /* error

message */ return 2; /* number of results */

/* create result table */ lua_newtable(L);

i = 1; while ((entry = readdir(dir)) != NULL) {

lua_pushnumber(L, i++); /* push key */ lua_pushstring(L, entry->d_name); /* push value */ lua_settable(L, -3);

closedir(dir); return 1; /* table is already on top */

Fungsi luaL_checkstring dari library bernilai sama dengan luaL_checknumber untuk nilai stringnya. Pada kondisi yang rumit, penerapan l_dir dapat menyebabkan kekurangan memori (kesalahan yang kecil pada kapasitas memori). Pemanggilan terhadap tiga fungsi Lua, yaitu lua_newtable, lua_pushstring, dan lua_settable dapat gagal karena memori tidak cukup. Jika salah satu dari pemanggilan fungsi ini gagal, maka akan menambah kesalahan dan menginterupsi (interrupt) l_dir, sehingga menyebabkan fungsi closedir tidak dapat dipanggil. Seperti yang telah kita bahas sebelumnya, pada kebanyakan program, kesalahan seperti ini bukan masalah besar. Jika ketika menjalankan program, komputer kehabisan memori, hal terbaik yang dapat dilakukan adalah mematikan komputernya. Meskipun demikian, pada Bab 29, kita akan melihat suatu penerapan alternatif untuk suatu fungsi directori yang dapat menghindari masalah seperti ini.