Lua原始碼剖析 lmathlib c

2021-06-14 20:19:38 字數 2825 閱讀 5596

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 ...