0、該模組是lua數學庫math模組的實現,讀該模組原始碼是為了學習lua與c的api以及註冊方法。
1、當在lua程式中,呼叫require("math")時,就會呼叫下面的luaopen_math函式,來註冊函式庫:
static const lual_reg mathlib = ,,,
,,,,
,,,,
,,,#if defined(lua_compat_log10)
,#endif,,
,,,,
,,,,
,,,};
luamod_api int luaopen_math (lua_state *l)
結構體例項mathlib中儲存了lua函式庫所有的介面,結構體lual_reg在lauxlib.h中的定義的:
typedef struct lual_reg lual_reg;
這裡的函式型別lua_cfunction在lua.h中定義的:typedef int (*lua_cfunction) (lua_state *l);所有用c實現
的lua函式,都是必須是這種型別,即乙個lua_state的引數,返回值為int。
函式luamod_api int luaopen_math (lua_state *l)呼叫auxiliary library中的介面lual_newlib(l,mathlib)註冊數學庫,在lauxlib.h中,我們可以看到該介面實質就是乙個巨集:
#define lual_newlib(l,l) (lual_newlibtable(l,l), lual_setfuncs(l,l,0)),
而lual_newlibtable在lauxlib.h實質上也是乙個巨集:
#define lual_newlibtable(l,l) \
lua_createtable(l, 0, sizeof(l)/sizeof((l)[0]) - 1)
它根據要註冊的結構體中的元素,建立乙個空的table,並壓入棧頂,在提前知道table中有多少元素的情況時,用介面lua_createtable來建立table比lua_newtable()更高效,注意上面減去1,是因為結構體mathlib最後乙個元素為。建立空的table,再利用介面lual_setfuncs把結構體mathlib中所有函式註冊到剛才建立的table中。
接下來**:
lua_pushnumber(l, pi);
lua_setfield(l, -2, "pi");
用來向函式庫中註冊常量pi,pi是乙個巨集,定義在lmathlib.c中,這兩行實質上就是通過lua的c api設定前面建立的table,其中key為"pi",value為pi。類似的lua_pushnumber(l, huge_val); lua_setfield(l, -2, "huge");註冊函式庫常量huge。huge_val是c語言在定義的乙個非常大的double正數。
最後注意函式luaopen_math()前面有乙個巨集luamod_api,它是在luaconf.h中定義的,也就是extern,它是用來標識那些標準開啟的庫函式,類似的lualib_api也是extern,它用來標識所有的auxiliary庫函式,lua_api也是extern,用來標識所有的core api函式。
2、由於math模組的api非常多,下面分析math模組中比較常用的api實現,首先看math.random()的實現,它對應的c實現如下:
static int math_random (lua_state *l)
case 1:
case 2:
default: return lual_error(l, "wrong number of arguments");
}return 1;
}函式static標識該函式只在模組內可見,這是乙個非常好的習慣。
lua_number r = (lua_number)(rand()%rand_max) / (lua_number)rand_max;
上面語句利用c語言的標準庫函式,生成乙個[0,1)之間的隨機數,這裡的lua_number是lua.h定義的lua_number型別,而lua_number是在luaconf.h中定義的乙個巨集,它標識lua中的數字型別,標準實現了double型。
lua_gettop(l)用來獲取棧頂元素的索引,也就是棧中元素的個數。
若棧中元素個數為0,即在lua中呼叫math.random(),這時候返回的[0,1)之間的值,即通過介面lua_pushnumber(l,r)把r壓入棧頂,返回這個值。
若棧中元素個數為1,即在lua中呼叫math.random(m),這時候返回的是[1,m]之間的值。介面lual_checknumber()用來檢測是否是乙個number,並返回這個number,lual_argcheck(),用來檢測條件是否為true,若不是,則會引起乙個錯誤。注意l_tg是在lmathlib.c中定義的乙個巨集:
#define l_tg(x) (x)
這樣做的目的,允許x在任何數學算術操作中可以在x後面加字尾l或f。比如當你想把lua的number型別該為long duoble時,便可以通過修改這個巨集的定義,改變操作number的c函式。比如使用sinl(或者使用sinf操作float型別)而不是sin。
若棧中元素個數為2,即在lua中呼叫math.random(n,m),這時候返回的是[n,m]之間的值,**玩家類似於只有乙個元素的情況。
若是其他情況,則呼叫介面int lual_error (lua_state *l, const char *fmt, ...);引發乙個錯誤,錯誤資訊是格式化的fmt。
用引數個數來區分功能上的微小差異是典型的lua風格,這是lua介面設計上的乙個慣例。
我們還可以注意到math_abs,math_acos等函式,都是直接用c中的庫函式來實現的。
原始碼剖析 Hashtable 原始碼剖析
hashtable同樣是基於雜湊表實現的,同樣每個元素都是key value對,其內部也是通過單鏈表解決衝突問題,容量不足 超過了閾值 時,同樣會自動增長。hashtable也是jdk1.0引入的類,是執行緒安全的,能用於多執行緒環境中。hashtable同樣實現了serializable介面,它支...
python原始碼剖析 Python原始碼剖析
第頁共 頁python 原始碼剖析 物件機制 1.物件 在python 的世界中,一切都是物件,乙個整數是乙個物件,乙個字串也是 乙個物件,更為奇妙的是,型別也是乙個物件,整數型別是乙個物件,字串類 型也是乙個物件。從 年guido 在那個聖誕節揭開 python 世界的大幕開始,一直到現在,pyt...
Erlang hotwheels原始碼剖析
整體構架 janus transport sup 實質為transport,supervisor,client instance supervisor 每個tcp會話建立乙個transport程序來處理對應客戶端的請求。janus topman sup 實質為topman,worker,topic ...